From b0d19035a44d2a9f76275860f4847dec9e485864 Mon Sep 17 00:00:00 2001 From: Srikanth Chekuri Date: Thu, 17 Apr 2025 15:54:36 +0530 Subject: [PATCH] chore: add where clause visitor implementation for query expression (#7564) --- grammar/FilterQuery.g4 | 7 +- pkg/parser/grammar/FilterQuery.interp | 4 +- pkg/parser/grammar/FilterQuery.tokens | 13 +- pkg/parser/grammar/FilterQueryLexer.interp | 5 +- pkg/parser/grammar/FilterQueryLexer.tokens | 13 +- pkg/parser/grammar/filterquery_lexer.go | 265 ++++---- pkg/parser/grammar/filterquery_parser.go | 36 +- pkg/parser/grammar/query_to_keys.go | 48 ++ pkg/parser/grammar/query_to_keys_test.go | 101 +++ pkg/parser/grammar/where_clause_visitor.go | 587 ++++++++++++++++ .../grammar/where_clause_visitor_test.go | 638 ++++++++++++++++++ pkg/telemetrylogs/condition_builder.go | 90 ++- pkg/telemetrylogs/condition_builder_test.go | 191 ++++++ pkg/telemetrylogs/const.go | 5 + pkg/types/telemetrytypes/field.go | 16 +- pkg/types/telemetrytypes/field_datatype.go | 42 ++ 16 files changed, 1877 insertions(+), 184 deletions(-) create mode 100644 pkg/parser/grammar/query_to_keys.go create mode 100644 pkg/parser/grammar/query_to_keys_test.go create mode 100644 pkg/parser/grammar/where_clause_visitor.go create mode 100644 pkg/parser/grammar/where_clause_visitor_test.go create mode 100644 pkg/telemetrylogs/const.go diff --git a/grammar/FilterQuery.g4 b/grammar/FilterQuery.g4 index 99e14bb1c9..a87e399232 100644 --- a/grammar/FilterQuery.g4 +++ b/grammar/FilterQuery.g4 @@ -104,7 +104,7 @@ fullText * ... */ functionCall - : (HAS | HASANY | HASALL | HASNONE) LPAREN functionParamList RPAREN + : (HAS | HASANY | HASALL) LPAREN functionParamList RPAREN ; // Function parameters can be keys, single scalar values, or arrays @@ -182,7 +182,6 @@ OR : [Oo][Rr] ; HAS : [Hh][Aa][Ss] ; HASANY : [Hh][Aa][Ss][Aa][Nn][Yy] ; HASALL : [Hh][Aa][Ss][Aa][Ll][Ll] ; -HASNONE : [Hh][Aa][Ss][Nn][Oo][Nn][Ee] ; // Potential boolean constants BOOL @@ -205,7 +204,7 @@ QUOTED_TEXT // Keys can have letters, digits, underscores, dots, and bracket pairs // e.g. service.name, service.namespace, db.queries[].query_duration KEY - : [a-zA-Z0-9_] [a-zA-Z0-9_.[\]]* + : [a-zA-Z0-9_] [a-zA-Z0-9_.*[\]]* ; // Ignore whitespace @@ -218,4 +217,4 @@ fragment DIGIT : [0-9] ; -FREETEXT : (~[ \t\r\n=()'"<>![\]])+ ; \ No newline at end of file +FREETEXT : (~[ \t\r\n=()'"<>!,[\]])+ ; diff --git a/pkg/parser/grammar/FilterQuery.interp b/pkg/parser/grammar/FilterQuery.interp index 5acc28a53a..154786c76c 100644 --- a/pkg/parser/grammar/FilterQuery.interp +++ b/pkg/parser/grammar/FilterQuery.interp @@ -33,7 +33,6 @@ null null null null -null token symbolic names: null @@ -64,7 +63,6 @@ OR HAS HASANY HASALL -HASNONE BOOL NUMBER QUOTED_TEXT @@ -93,4 +91,4 @@ key atn: -[4, 1, 34, 212, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 5, 2, 43, 8, 2, 10, 2, 12, 2, 46, 9, 2, 1, 3, 1, 3, 1, 3, 1, 3, 5, 3, 52, 8, 3, 10, 3, 12, 3, 55, 9, 3, 1, 4, 3, 4, 58, 8, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 70, 8, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 148, 8, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 3, 7, 160, 8, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 174, 8, 8, 1, 9, 1, 9, 1, 9, 5, 9, 179, 8, 9, 10, 9, 12, 9, 182, 9, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 5, 12, 194, 8, 12, 10, 12, 12, 12, 197, 9, 12, 1, 13, 1, 13, 1, 13, 3, 13, 202, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 0, 0, 17, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 0, 6, 1, 0, 7, 8, 2, 0, 13, 13, 15, 15, 2, 0, 14, 14, 16, 16, 2, 0, 31, 31, 34, 34, 1, 0, 25, 28, 1, 0, 29, 32, 225, 0, 34, 1, 0, 0, 0, 2, 37, 1, 0, 0, 0, 4, 39, 1, 0, 0, 0, 6, 47, 1, 0, 0, 0, 8, 57, 1, 0, 0, 0, 10, 69, 1, 0, 0, 0, 12, 147, 1, 0, 0, 0, 14, 159, 1, 0, 0, 0, 16, 173, 1, 0, 0, 0, 18, 175, 1, 0, 0, 0, 20, 183, 1, 0, 0, 0, 22, 185, 1, 0, 0, 0, 24, 190, 1, 0, 0, 0, 26, 201, 1, 0, 0, 0, 28, 203, 1, 0, 0, 0, 30, 207, 1, 0, 0, 0, 32, 209, 1, 0, 0, 0, 34, 35, 3, 2, 1, 0, 35, 36, 5, 0, 0, 1, 36, 1, 1, 0, 0, 0, 37, 38, 3, 4, 2, 0, 38, 3, 1, 0, 0, 0, 39, 44, 3, 6, 3, 0, 40, 41, 5, 24, 0, 0, 41, 43, 3, 6, 3, 0, 42, 40, 1, 0, 0, 0, 43, 46, 1, 0, 0, 0, 44, 42, 1, 0, 0, 0, 44, 45, 1, 0, 0, 0, 45, 5, 1, 0, 0, 0, 46, 44, 1, 0, 0, 0, 47, 53, 3, 8, 4, 0, 48, 49, 5, 23, 0, 0, 49, 52, 3, 8, 4, 0, 50, 52, 3, 8, 4, 0, 51, 48, 1, 0, 0, 0, 51, 50, 1, 0, 0, 0, 52, 55, 1, 0, 0, 0, 53, 51, 1, 0, 0, 0, 53, 54, 1, 0, 0, 0, 54, 7, 1, 0, 0, 0, 55, 53, 1, 0, 0, 0, 56, 58, 5, 22, 0, 0, 57, 56, 1, 0, 0, 0, 57, 58, 1, 0, 0, 0, 58, 59, 1, 0, 0, 0, 59, 60, 3, 10, 5, 0, 60, 9, 1, 0, 0, 0, 61, 62, 5, 1, 0, 0, 62, 63, 3, 4, 2, 0, 63, 64, 5, 2, 0, 0, 64, 70, 1, 0, 0, 0, 65, 70, 3, 12, 6, 0, 66, 70, 3, 22, 11, 0, 67, 70, 3, 20, 10, 0, 68, 70, 3, 32, 16, 0, 69, 61, 1, 0, 0, 0, 69, 65, 1, 0, 0, 0, 69, 66, 1, 0, 0, 0, 69, 67, 1, 0, 0, 0, 69, 68, 1, 0, 0, 0, 70, 11, 1, 0, 0, 0, 71, 72, 3, 32, 16, 0, 72, 73, 5, 6, 0, 0, 73, 74, 3, 30, 15, 0, 74, 148, 1, 0, 0, 0, 75, 76, 3, 32, 16, 0, 76, 77, 7, 0, 0, 0, 77, 78, 3, 30, 15, 0, 78, 148, 1, 0, 0, 0, 79, 80, 3, 32, 16, 0, 80, 81, 5, 9, 0, 0, 81, 82, 3, 30, 15, 0, 82, 148, 1, 0, 0, 0, 83, 84, 3, 32, 16, 0, 84, 85, 5, 10, 0, 0, 85, 86, 3, 30, 15, 0, 86, 148, 1, 0, 0, 0, 87, 88, 3, 32, 16, 0, 88, 89, 5, 11, 0, 0, 89, 90, 3, 30, 15, 0, 90, 148, 1, 0, 0, 0, 91, 92, 3, 32, 16, 0, 92, 93, 5, 12, 0, 0, 93, 94, 3, 30, 15, 0, 94, 148, 1, 0, 0, 0, 95, 96, 3, 32, 16, 0, 96, 97, 7, 1, 0, 0, 97, 98, 3, 30, 15, 0, 98, 148, 1, 0, 0, 0, 99, 100, 3, 32, 16, 0, 100, 101, 7, 2, 0, 0, 101, 102, 3, 30, 15, 0, 102, 148, 1, 0, 0, 0, 103, 104, 3, 32, 16, 0, 104, 105, 5, 17, 0, 0, 105, 106, 3, 30, 15, 0, 106, 107, 5, 23, 0, 0, 107, 108, 3, 30, 15, 0, 108, 148, 1, 0, 0, 0, 109, 110, 3, 32, 16, 0, 110, 111, 5, 22, 0, 0, 111, 112, 5, 17, 0, 0, 112, 113, 3, 30, 15, 0, 113, 114, 5, 23, 0, 0, 114, 115, 3, 30, 15, 0, 115, 148, 1, 0, 0, 0, 116, 117, 3, 32, 16, 0, 117, 118, 3, 14, 7, 0, 118, 148, 1, 0, 0, 0, 119, 120, 3, 32, 16, 0, 120, 121, 3, 16, 8, 0, 121, 148, 1, 0, 0, 0, 122, 123, 3, 32, 16, 0, 123, 124, 5, 18, 0, 0, 124, 148, 1, 0, 0, 0, 125, 126, 3, 32, 16, 0, 126, 127, 5, 22, 0, 0, 127, 128, 5, 18, 0, 0, 128, 148, 1, 0, 0, 0, 129, 130, 3, 32, 16, 0, 130, 131, 5, 19, 0, 0, 131, 132, 3, 30, 15, 0, 132, 148, 1, 0, 0, 0, 133, 134, 3, 32, 16, 0, 134, 135, 5, 22, 0, 0, 135, 136, 5, 19, 0, 0, 136, 137, 3, 30, 15, 0, 137, 148, 1, 0, 0, 0, 138, 139, 3, 32, 16, 0, 139, 140, 5, 20, 0, 0, 140, 141, 3, 30, 15, 0, 141, 148, 1, 0, 0, 0, 142, 143, 3, 32, 16, 0, 143, 144, 5, 22, 0, 0, 144, 145, 5, 20, 0, 0, 145, 146, 3, 30, 15, 0, 146, 148, 1, 0, 0, 0, 147, 71, 1, 0, 0, 0, 147, 75, 1, 0, 0, 0, 147, 79, 1, 0, 0, 0, 147, 83, 1, 0, 0, 0, 147, 87, 1, 0, 0, 0, 147, 91, 1, 0, 0, 0, 147, 95, 1, 0, 0, 0, 147, 99, 1, 0, 0, 0, 147, 103, 1, 0, 0, 0, 147, 109, 1, 0, 0, 0, 147, 116, 1, 0, 0, 0, 147, 119, 1, 0, 0, 0, 147, 122, 1, 0, 0, 0, 147, 125, 1, 0, 0, 0, 147, 129, 1, 0, 0, 0, 147, 133, 1, 0, 0, 0, 147, 138, 1, 0, 0, 0, 147, 142, 1, 0, 0, 0, 148, 13, 1, 0, 0, 0, 149, 150, 5, 21, 0, 0, 150, 151, 5, 1, 0, 0, 151, 152, 3, 18, 9, 0, 152, 153, 5, 2, 0, 0, 153, 160, 1, 0, 0, 0, 154, 155, 5, 21, 0, 0, 155, 156, 5, 3, 0, 0, 156, 157, 3, 18, 9, 0, 157, 158, 5, 4, 0, 0, 158, 160, 1, 0, 0, 0, 159, 149, 1, 0, 0, 0, 159, 154, 1, 0, 0, 0, 160, 15, 1, 0, 0, 0, 161, 162, 5, 22, 0, 0, 162, 163, 5, 21, 0, 0, 163, 164, 5, 1, 0, 0, 164, 165, 3, 18, 9, 0, 165, 166, 5, 2, 0, 0, 166, 174, 1, 0, 0, 0, 167, 168, 5, 22, 0, 0, 168, 169, 5, 21, 0, 0, 169, 170, 5, 3, 0, 0, 170, 171, 3, 18, 9, 0, 171, 172, 5, 4, 0, 0, 172, 174, 1, 0, 0, 0, 173, 161, 1, 0, 0, 0, 173, 167, 1, 0, 0, 0, 174, 17, 1, 0, 0, 0, 175, 180, 3, 30, 15, 0, 176, 177, 5, 5, 0, 0, 177, 179, 3, 30, 15, 0, 178, 176, 1, 0, 0, 0, 179, 182, 1, 0, 0, 0, 180, 178, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 19, 1, 0, 0, 0, 182, 180, 1, 0, 0, 0, 183, 184, 7, 3, 0, 0, 184, 21, 1, 0, 0, 0, 185, 186, 7, 4, 0, 0, 186, 187, 5, 1, 0, 0, 187, 188, 3, 24, 12, 0, 188, 189, 5, 2, 0, 0, 189, 23, 1, 0, 0, 0, 190, 195, 3, 26, 13, 0, 191, 192, 5, 5, 0, 0, 192, 194, 3, 26, 13, 0, 193, 191, 1, 0, 0, 0, 194, 197, 1, 0, 0, 0, 195, 193, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 25, 1, 0, 0, 0, 197, 195, 1, 0, 0, 0, 198, 202, 3, 32, 16, 0, 199, 202, 3, 30, 15, 0, 200, 202, 3, 28, 14, 0, 201, 198, 1, 0, 0, 0, 201, 199, 1, 0, 0, 0, 201, 200, 1, 0, 0, 0, 202, 27, 1, 0, 0, 0, 203, 204, 5, 3, 0, 0, 204, 205, 3, 18, 9, 0, 205, 206, 5, 4, 0, 0, 206, 29, 1, 0, 0, 0, 207, 208, 7, 5, 0, 0, 208, 31, 1, 0, 0, 0, 209, 210, 5, 32, 0, 0, 210, 33, 1, 0, 0, 0, 11, 44, 51, 53, 57, 69, 147, 159, 173, 180, 195, 201] \ No newline at end of file +[4, 1, 33, 212, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 5, 2, 43, 8, 2, 10, 2, 12, 2, 46, 9, 2, 1, 3, 1, 3, 1, 3, 1, 3, 5, 3, 52, 8, 3, 10, 3, 12, 3, 55, 9, 3, 1, 4, 3, 4, 58, 8, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 70, 8, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 148, 8, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 3, 7, 160, 8, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 174, 8, 8, 1, 9, 1, 9, 1, 9, 5, 9, 179, 8, 9, 10, 9, 12, 9, 182, 9, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 5, 12, 194, 8, 12, 10, 12, 12, 12, 197, 9, 12, 1, 13, 1, 13, 1, 13, 3, 13, 202, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 0, 0, 17, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 0, 6, 1, 0, 7, 8, 2, 0, 13, 13, 15, 15, 2, 0, 14, 14, 16, 16, 2, 0, 30, 30, 33, 33, 1, 0, 25, 27, 1, 0, 28, 31, 225, 0, 34, 1, 0, 0, 0, 2, 37, 1, 0, 0, 0, 4, 39, 1, 0, 0, 0, 6, 47, 1, 0, 0, 0, 8, 57, 1, 0, 0, 0, 10, 69, 1, 0, 0, 0, 12, 147, 1, 0, 0, 0, 14, 159, 1, 0, 0, 0, 16, 173, 1, 0, 0, 0, 18, 175, 1, 0, 0, 0, 20, 183, 1, 0, 0, 0, 22, 185, 1, 0, 0, 0, 24, 190, 1, 0, 0, 0, 26, 201, 1, 0, 0, 0, 28, 203, 1, 0, 0, 0, 30, 207, 1, 0, 0, 0, 32, 209, 1, 0, 0, 0, 34, 35, 3, 2, 1, 0, 35, 36, 5, 0, 0, 1, 36, 1, 1, 0, 0, 0, 37, 38, 3, 4, 2, 0, 38, 3, 1, 0, 0, 0, 39, 44, 3, 6, 3, 0, 40, 41, 5, 24, 0, 0, 41, 43, 3, 6, 3, 0, 42, 40, 1, 0, 0, 0, 43, 46, 1, 0, 0, 0, 44, 42, 1, 0, 0, 0, 44, 45, 1, 0, 0, 0, 45, 5, 1, 0, 0, 0, 46, 44, 1, 0, 0, 0, 47, 53, 3, 8, 4, 0, 48, 49, 5, 23, 0, 0, 49, 52, 3, 8, 4, 0, 50, 52, 3, 8, 4, 0, 51, 48, 1, 0, 0, 0, 51, 50, 1, 0, 0, 0, 52, 55, 1, 0, 0, 0, 53, 51, 1, 0, 0, 0, 53, 54, 1, 0, 0, 0, 54, 7, 1, 0, 0, 0, 55, 53, 1, 0, 0, 0, 56, 58, 5, 22, 0, 0, 57, 56, 1, 0, 0, 0, 57, 58, 1, 0, 0, 0, 58, 59, 1, 0, 0, 0, 59, 60, 3, 10, 5, 0, 60, 9, 1, 0, 0, 0, 61, 62, 5, 1, 0, 0, 62, 63, 3, 4, 2, 0, 63, 64, 5, 2, 0, 0, 64, 70, 1, 0, 0, 0, 65, 70, 3, 12, 6, 0, 66, 70, 3, 22, 11, 0, 67, 70, 3, 20, 10, 0, 68, 70, 3, 32, 16, 0, 69, 61, 1, 0, 0, 0, 69, 65, 1, 0, 0, 0, 69, 66, 1, 0, 0, 0, 69, 67, 1, 0, 0, 0, 69, 68, 1, 0, 0, 0, 70, 11, 1, 0, 0, 0, 71, 72, 3, 32, 16, 0, 72, 73, 5, 6, 0, 0, 73, 74, 3, 30, 15, 0, 74, 148, 1, 0, 0, 0, 75, 76, 3, 32, 16, 0, 76, 77, 7, 0, 0, 0, 77, 78, 3, 30, 15, 0, 78, 148, 1, 0, 0, 0, 79, 80, 3, 32, 16, 0, 80, 81, 5, 9, 0, 0, 81, 82, 3, 30, 15, 0, 82, 148, 1, 0, 0, 0, 83, 84, 3, 32, 16, 0, 84, 85, 5, 10, 0, 0, 85, 86, 3, 30, 15, 0, 86, 148, 1, 0, 0, 0, 87, 88, 3, 32, 16, 0, 88, 89, 5, 11, 0, 0, 89, 90, 3, 30, 15, 0, 90, 148, 1, 0, 0, 0, 91, 92, 3, 32, 16, 0, 92, 93, 5, 12, 0, 0, 93, 94, 3, 30, 15, 0, 94, 148, 1, 0, 0, 0, 95, 96, 3, 32, 16, 0, 96, 97, 7, 1, 0, 0, 97, 98, 3, 30, 15, 0, 98, 148, 1, 0, 0, 0, 99, 100, 3, 32, 16, 0, 100, 101, 7, 2, 0, 0, 101, 102, 3, 30, 15, 0, 102, 148, 1, 0, 0, 0, 103, 104, 3, 32, 16, 0, 104, 105, 5, 17, 0, 0, 105, 106, 3, 30, 15, 0, 106, 107, 5, 23, 0, 0, 107, 108, 3, 30, 15, 0, 108, 148, 1, 0, 0, 0, 109, 110, 3, 32, 16, 0, 110, 111, 5, 22, 0, 0, 111, 112, 5, 17, 0, 0, 112, 113, 3, 30, 15, 0, 113, 114, 5, 23, 0, 0, 114, 115, 3, 30, 15, 0, 115, 148, 1, 0, 0, 0, 116, 117, 3, 32, 16, 0, 117, 118, 3, 14, 7, 0, 118, 148, 1, 0, 0, 0, 119, 120, 3, 32, 16, 0, 120, 121, 3, 16, 8, 0, 121, 148, 1, 0, 0, 0, 122, 123, 3, 32, 16, 0, 123, 124, 5, 18, 0, 0, 124, 148, 1, 0, 0, 0, 125, 126, 3, 32, 16, 0, 126, 127, 5, 22, 0, 0, 127, 128, 5, 18, 0, 0, 128, 148, 1, 0, 0, 0, 129, 130, 3, 32, 16, 0, 130, 131, 5, 19, 0, 0, 131, 132, 3, 30, 15, 0, 132, 148, 1, 0, 0, 0, 133, 134, 3, 32, 16, 0, 134, 135, 5, 22, 0, 0, 135, 136, 5, 19, 0, 0, 136, 137, 3, 30, 15, 0, 137, 148, 1, 0, 0, 0, 138, 139, 3, 32, 16, 0, 139, 140, 5, 20, 0, 0, 140, 141, 3, 30, 15, 0, 141, 148, 1, 0, 0, 0, 142, 143, 3, 32, 16, 0, 143, 144, 5, 22, 0, 0, 144, 145, 5, 20, 0, 0, 145, 146, 3, 30, 15, 0, 146, 148, 1, 0, 0, 0, 147, 71, 1, 0, 0, 0, 147, 75, 1, 0, 0, 0, 147, 79, 1, 0, 0, 0, 147, 83, 1, 0, 0, 0, 147, 87, 1, 0, 0, 0, 147, 91, 1, 0, 0, 0, 147, 95, 1, 0, 0, 0, 147, 99, 1, 0, 0, 0, 147, 103, 1, 0, 0, 0, 147, 109, 1, 0, 0, 0, 147, 116, 1, 0, 0, 0, 147, 119, 1, 0, 0, 0, 147, 122, 1, 0, 0, 0, 147, 125, 1, 0, 0, 0, 147, 129, 1, 0, 0, 0, 147, 133, 1, 0, 0, 0, 147, 138, 1, 0, 0, 0, 147, 142, 1, 0, 0, 0, 148, 13, 1, 0, 0, 0, 149, 150, 5, 21, 0, 0, 150, 151, 5, 1, 0, 0, 151, 152, 3, 18, 9, 0, 152, 153, 5, 2, 0, 0, 153, 160, 1, 0, 0, 0, 154, 155, 5, 21, 0, 0, 155, 156, 5, 3, 0, 0, 156, 157, 3, 18, 9, 0, 157, 158, 5, 4, 0, 0, 158, 160, 1, 0, 0, 0, 159, 149, 1, 0, 0, 0, 159, 154, 1, 0, 0, 0, 160, 15, 1, 0, 0, 0, 161, 162, 5, 22, 0, 0, 162, 163, 5, 21, 0, 0, 163, 164, 5, 1, 0, 0, 164, 165, 3, 18, 9, 0, 165, 166, 5, 2, 0, 0, 166, 174, 1, 0, 0, 0, 167, 168, 5, 22, 0, 0, 168, 169, 5, 21, 0, 0, 169, 170, 5, 3, 0, 0, 170, 171, 3, 18, 9, 0, 171, 172, 5, 4, 0, 0, 172, 174, 1, 0, 0, 0, 173, 161, 1, 0, 0, 0, 173, 167, 1, 0, 0, 0, 174, 17, 1, 0, 0, 0, 175, 180, 3, 30, 15, 0, 176, 177, 5, 5, 0, 0, 177, 179, 3, 30, 15, 0, 178, 176, 1, 0, 0, 0, 179, 182, 1, 0, 0, 0, 180, 178, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 19, 1, 0, 0, 0, 182, 180, 1, 0, 0, 0, 183, 184, 7, 3, 0, 0, 184, 21, 1, 0, 0, 0, 185, 186, 7, 4, 0, 0, 186, 187, 5, 1, 0, 0, 187, 188, 3, 24, 12, 0, 188, 189, 5, 2, 0, 0, 189, 23, 1, 0, 0, 0, 190, 195, 3, 26, 13, 0, 191, 192, 5, 5, 0, 0, 192, 194, 3, 26, 13, 0, 193, 191, 1, 0, 0, 0, 194, 197, 1, 0, 0, 0, 195, 193, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 25, 1, 0, 0, 0, 197, 195, 1, 0, 0, 0, 198, 202, 3, 32, 16, 0, 199, 202, 3, 30, 15, 0, 200, 202, 3, 28, 14, 0, 201, 198, 1, 0, 0, 0, 201, 199, 1, 0, 0, 0, 201, 200, 1, 0, 0, 0, 202, 27, 1, 0, 0, 0, 203, 204, 5, 3, 0, 0, 204, 205, 3, 18, 9, 0, 205, 206, 5, 4, 0, 0, 206, 29, 1, 0, 0, 0, 207, 208, 7, 5, 0, 0, 208, 31, 1, 0, 0, 0, 209, 210, 5, 31, 0, 0, 210, 33, 1, 0, 0, 0, 11, 44, 51, 53, 57, 69, 147, 159, 173, 180, 195, 201] \ No newline at end of file diff --git a/pkg/parser/grammar/FilterQuery.tokens b/pkg/parser/grammar/FilterQuery.tokens index ca38d44fa5..e6c7864740 100644 --- a/pkg/parser/grammar/FilterQuery.tokens +++ b/pkg/parser/grammar/FilterQuery.tokens @@ -25,13 +25,12 @@ OR=24 HAS=25 HASANY=26 HASALL=27 -HASNONE=28 -BOOL=29 -NUMBER=30 -QUOTED_TEXT=31 -KEY=32 -WS=33 -FREETEXT=34 +BOOL=28 +NUMBER=29 +QUOTED_TEXT=30 +KEY=31 +WS=32 +FREETEXT=33 '('=1 ')'=2 '['=3 diff --git a/pkg/parser/grammar/FilterQueryLexer.interp b/pkg/parser/grammar/FilterQueryLexer.interp index 3808e111e1..5a08c7b188 100644 --- a/pkg/parser/grammar/FilterQueryLexer.interp +++ b/pkg/parser/grammar/FilterQueryLexer.interp @@ -33,7 +33,6 @@ null null null null -null token symbolic names: null @@ -64,7 +63,6 @@ OR HAS HASANY HASALL -HASNONE BOOL NUMBER QUOTED_TEXT @@ -100,7 +98,6 @@ OR HAS HASANY HASALL -HASNONE BOOL NUMBER QUOTED_TEXT @@ -117,4 +114,4 @@ mode names: DEFAULT_MODE atn: -[4, 0, 34, 280, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 3, 5, 85, 8, 5, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 4, 13, 112, 8, 13, 11, 13, 12, 13, 113, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 4, 15, 131, 8, 15, 11, 15, 12, 15, 132, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 3, 17, 155, 8, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 3, 19, 172, 8, 19, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 3, 28, 223, 8, 28, 1, 29, 4, 29, 226, 8, 29, 11, 29, 12, 29, 227, 1, 29, 1, 29, 4, 29, 232, 8, 29, 11, 29, 12, 29, 233, 3, 29, 236, 8, 29, 1, 30, 1, 30, 1, 30, 1, 30, 5, 30, 242, 8, 30, 10, 30, 12, 30, 245, 9, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 5, 30, 252, 8, 30, 10, 30, 12, 30, 255, 9, 30, 1, 30, 3, 30, 258, 8, 30, 1, 31, 1, 31, 5, 31, 262, 8, 31, 10, 31, 12, 31, 265, 9, 31, 1, 32, 4, 32, 268, 8, 32, 11, 32, 12, 32, 269, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 4, 34, 277, 8, 34, 11, 34, 12, 34, 278, 0, 0, 35, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 33, 67, 0, 69, 34, 1, 0, 29, 2, 0, 76, 76, 108, 108, 2, 0, 73, 73, 105, 105, 2, 0, 75, 75, 107, 107, 2, 0, 69, 69, 101, 101, 2, 0, 78, 78, 110, 110, 2, 0, 79, 79, 111, 111, 2, 0, 84, 84, 116, 116, 2, 0, 9, 9, 32, 32, 2, 0, 66, 66, 98, 98, 2, 0, 87, 87, 119, 119, 2, 0, 88, 88, 120, 120, 2, 0, 83, 83, 115, 115, 2, 0, 82, 82, 114, 114, 2, 0, 71, 71, 103, 103, 2, 0, 80, 80, 112, 112, 2, 0, 67, 67, 99, 99, 2, 0, 65, 65, 97, 97, 2, 0, 68, 68, 100, 100, 2, 0, 72, 72, 104, 104, 2, 0, 89, 89, 121, 121, 2, 0, 85, 85, 117, 117, 2, 0, 70, 70, 102, 102, 2, 0, 34, 34, 92, 92, 2, 0, 39, 39, 92, 92, 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, 6, 0, 46, 46, 48, 57, 65, 91, 93, 93, 95, 95, 97, 122, 3, 0, 9, 10, 13, 13, 32, 32, 1, 0, 48, 57, 7, 0, 9, 10, 13, 13, 32, 34, 39, 41, 60, 62, 91, 91, 93, 93, 295, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 1, 71, 1, 0, 0, 0, 3, 73, 1, 0, 0, 0, 5, 75, 1, 0, 0, 0, 7, 77, 1, 0, 0, 0, 9, 79, 1, 0, 0, 0, 11, 84, 1, 0, 0, 0, 13, 86, 1, 0, 0, 0, 15, 89, 1, 0, 0, 0, 17, 92, 1, 0, 0, 0, 19, 94, 1, 0, 0, 0, 21, 97, 1, 0, 0, 0, 23, 99, 1, 0, 0, 0, 25, 102, 1, 0, 0, 0, 27, 107, 1, 0, 0, 0, 29, 120, 1, 0, 0, 0, 31, 126, 1, 0, 0, 0, 33, 140, 1, 0, 0, 0, 35, 148, 1, 0, 0, 0, 37, 156, 1, 0, 0, 0, 39, 163, 1, 0, 0, 0, 41, 173, 1, 0, 0, 0, 43, 176, 1, 0, 0, 0, 45, 180, 1, 0, 0, 0, 47, 184, 1, 0, 0, 0, 49, 187, 1, 0, 0, 0, 51, 191, 1, 0, 0, 0, 53, 198, 1, 0, 0, 0, 55, 205, 1, 0, 0, 0, 57, 222, 1, 0, 0, 0, 59, 225, 1, 0, 0, 0, 61, 257, 1, 0, 0, 0, 63, 259, 1, 0, 0, 0, 65, 267, 1, 0, 0, 0, 67, 273, 1, 0, 0, 0, 69, 276, 1, 0, 0, 0, 71, 72, 5, 40, 0, 0, 72, 2, 1, 0, 0, 0, 73, 74, 5, 41, 0, 0, 74, 4, 1, 0, 0, 0, 75, 76, 5, 91, 0, 0, 76, 6, 1, 0, 0, 0, 77, 78, 5, 93, 0, 0, 78, 8, 1, 0, 0, 0, 79, 80, 5, 44, 0, 0, 80, 10, 1, 0, 0, 0, 81, 85, 5, 61, 0, 0, 82, 83, 5, 61, 0, 0, 83, 85, 5, 61, 0, 0, 84, 81, 1, 0, 0, 0, 84, 82, 1, 0, 0, 0, 85, 12, 1, 0, 0, 0, 86, 87, 5, 33, 0, 0, 87, 88, 5, 61, 0, 0, 88, 14, 1, 0, 0, 0, 89, 90, 5, 60, 0, 0, 90, 91, 5, 62, 0, 0, 91, 16, 1, 0, 0, 0, 92, 93, 5, 60, 0, 0, 93, 18, 1, 0, 0, 0, 94, 95, 5, 60, 0, 0, 95, 96, 5, 61, 0, 0, 96, 20, 1, 0, 0, 0, 97, 98, 5, 62, 0, 0, 98, 22, 1, 0, 0, 0, 99, 100, 5, 62, 0, 0, 100, 101, 5, 61, 0, 0, 101, 24, 1, 0, 0, 0, 102, 103, 7, 0, 0, 0, 103, 104, 7, 1, 0, 0, 104, 105, 7, 2, 0, 0, 105, 106, 7, 3, 0, 0, 106, 26, 1, 0, 0, 0, 107, 108, 7, 4, 0, 0, 108, 109, 7, 5, 0, 0, 109, 111, 7, 6, 0, 0, 110, 112, 7, 7, 0, 0, 111, 110, 1, 0, 0, 0, 112, 113, 1, 0, 0, 0, 113, 111, 1, 0, 0, 0, 113, 114, 1, 0, 0, 0, 114, 115, 1, 0, 0, 0, 115, 116, 7, 0, 0, 0, 116, 117, 7, 1, 0, 0, 117, 118, 7, 2, 0, 0, 118, 119, 7, 3, 0, 0, 119, 28, 1, 0, 0, 0, 120, 121, 7, 1, 0, 0, 121, 122, 7, 0, 0, 0, 122, 123, 7, 1, 0, 0, 123, 124, 7, 2, 0, 0, 124, 125, 7, 3, 0, 0, 125, 30, 1, 0, 0, 0, 126, 127, 7, 4, 0, 0, 127, 128, 7, 5, 0, 0, 128, 130, 7, 6, 0, 0, 129, 131, 7, 7, 0, 0, 130, 129, 1, 0, 0, 0, 131, 132, 1, 0, 0, 0, 132, 130, 1, 0, 0, 0, 132, 133, 1, 0, 0, 0, 133, 134, 1, 0, 0, 0, 134, 135, 7, 1, 0, 0, 135, 136, 7, 0, 0, 0, 136, 137, 7, 1, 0, 0, 137, 138, 7, 2, 0, 0, 138, 139, 7, 3, 0, 0, 139, 32, 1, 0, 0, 0, 140, 141, 7, 8, 0, 0, 141, 142, 7, 3, 0, 0, 142, 143, 7, 6, 0, 0, 143, 144, 7, 9, 0, 0, 144, 145, 7, 3, 0, 0, 145, 146, 7, 3, 0, 0, 146, 147, 7, 4, 0, 0, 147, 34, 1, 0, 0, 0, 148, 149, 7, 3, 0, 0, 149, 150, 7, 10, 0, 0, 150, 151, 7, 1, 0, 0, 151, 152, 7, 11, 0, 0, 152, 154, 7, 6, 0, 0, 153, 155, 7, 11, 0, 0, 154, 153, 1, 0, 0, 0, 154, 155, 1, 0, 0, 0, 155, 36, 1, 0, 0, 0, 156, 157, 7, 12, 0, 0, 157, 158, 7, 3, 0, 0, 158, 159, 7, 13, 0, 0, 159, 160, 7, 3, 0, 0, 160, 161, 7, 10, 0, 0, 161, 162, 7, 14, 0, 0, 162, 38, 1, 0, 0, 0, 163, 164, 7, 15, 0, 0, 164, 165, 7, 5, 0, 0, 165, 166, 7, 4, 0, 0, 166, 167, 7, 6, 0, 0, 167, 168, 7, 16, 0, 0, 168, 169, 7, 1, 0, 0, 169, 171, 7, 4, 0, 0, 170, 172, 7, 11, 0, 0, 171, 170, 1, 0, 0, 0, 171, 172, 1, 0, 0, 0, 172, 40, 1, 0, 0, 0, 173, 174, 7, 1, 0, 0, 174, 175, 7, 4, 0, 0, 175, 42, 1, 0, 0, 0, 176, 177, 7, 4, 0, 0, 177, 178, 7, 5, 0, 0, 178, 179, 7, 6, 0, 0, 179, 44, 1, 0, 0, 0, 180, 181, 7, 16, 0, 0, 181, 182, 7, 4, 0, 0, 182, 183, 7, 17, 0, 0, 183, 46, 1, 0, 0, 0, 184, 185, 7, 5, 0, 0, 185, 186, 7, 12, 0, 0, 186, 48, 1, 0, 0, 0, 187, 188, 7, 18, 0, 0, 188, 189, 7, 16, 0, 0, 189, 190, 7, 11, 0, 0, 190, 50, 1, 0, 0, 0, 191, 192, 7, 18, 0, 0, 192, 193, 7, 16, 0, 0, 193, 194, 7, 11, 0, 0, 194, 195, 7, 16, 0, 0, 195, 196, 7, 4, 0, 0, 196, 197, 7, 19, 0, 0, 197, 52, 1, 0, 0, 0, 198, 199, 7, 18, 0, 0, 199, 200, 7, 16, 0, 0, 200, 201, 7, 11, 0, 0, 201, 202, 7, 16, 0, 0, 202, 203, 7, 0, 0, 0, 203, 204, 7, 0, 0, 0, 204, 54, 1, 0, 0, 0, 205, 206, 7, 18, 0, 0, 206, 207, 7, 16, 0, 0, 207, 208, 7, 11, 0, 0, 208, 209, 7, 4, 0, 0, 209, 210, 7, 5, 0, 0, 210, 211, 7, 4, 0, 0, 211, 212, 7, 3, 0, 0, 212, 56, 1, 0, 0, 0, 213, 214, 7, 6, 0, 0, 214, 215, 7, 12, 0, 0, 215, 216, 7, 20, 0, 0, 216, 223, 7, 3, 0, 0, 217, 218, 7, 21, 0, 0, 218, 219, 7, 16, 0, 0, 219, 220, 7, 0, 0, 0, 220, 221, 7, 11, 0, 0, 221, 223, 7, 3, 0, 0, 222, 213, 1, 0, 0, 0, 222, 217, 1, 0, 0, 0, 223, 58, 1, 0, 0, 0, 224, 226, 3, 67, 33, 0, 225, 224, 1, 0, 0, 0, 226, 227, 1, 0, 0, 0, 227, 225, 1, 0, 0, 0, 227, 228, 1, 0, 0, 0, 228, 235, 1, 0, 0, 0, 229, 231, 5, 46, 0, 0, 230, 232, 3, 67, 33, 0, 231, 230, 1, 0, 0, 0, 232, 233, 1, 0, 0, 0, 233, 231, 1, 0, 0, 0, 233, 234, 1, 0, 0, 0, 234, 236, 1, 0, 0, 0, 235, 229, 1, 0, 0, 0, 235, 236, 1, 0, 0, 0, 236, 60, 1, 0, 0, 0, 237, 243, 5, 34, 0, 0, 238, 242, 8, 22, 0, 0, 239, 240, 5, 92, 0, 0, 240, 242, 9, 0, 0, 0, 241, 238, 1, 0, 0, 0, 241, 239, 1, 0, 0, 0, 242, 245, 1, 0, 0, 0, 243, 241, 1, 0, 0, 0, 243, 244, 1, 0, 0, 0, 244, 246, 1, 0, 0, 0, 245, 243, 1, 0, 0, 0, 246, 258, 5, 34, 0, 0, 247, 253, 5, 39, 0, 0, 248, 252, 8, 23, 0, 0, 249, 250, 5, 92, 0, 0, 250, 252, 9, 0, 0, 0, 251, 248, 1, 0, 0, 0, 251, 249, 1, 0, 0, 0, 252, 255, 1, 0, 0, 0, 253, 251, 1, 0, 0, 0, 253, 254, 1, 0, 0, 0, 254, 256, 1, 0, 0, 0, 255, 253, 1, 0, 0, 0, 256, 258, 5, 39, 0, 0, 257, 237, 1, 0, 0, 0, 257, 247, 1, 0, 0, 0, 258, 62, 1, 0, 0, 0, 259, 263, 7, 24, 0, 0, 260, 262, 7, 25, 0, 0, 261, 260, 1, 0, 0, 0, 262, 265, 1, 0, 0, 0, 263, 261, 1, 0, 0, 0, 263, 264, 1, 0, 0, 0, 264, 64, 1, 0, 0, 0, 265, 263, 1, 0, 0, 0, 266, 268, 7, 26, 0, 0, 267, 266, 1, 0, 0, 0, 268, 269, 1, 0, 0, 0, 269, 267, 1, 0, 0, 0, 269, 270, 1, 0, 0, 0, 270, 271, 1, 0, 0, 0, 271, 272, 6, 32, 0, 0, 272, 66, 1, 0, 0, 0, 273, 274, 7, 27, 0, 0, 274, 68, 1, 0, 0, 0, 275, 277, 8, 28, 0, 0, 276, 275, 1, 0, 0, 0, 277, 278, 1, 0, 0, 0, 278, 276, 1, 0, 0, 0, 278, 279, 1, 0, 0, 0, 279, 70, 1, 0, 0, 0, 18, 0, 84, 113, 132, 154, 171, 222, 227, 233, 235, 241, 243, 251, 253, 257, 263, 269, 278, 1, 6, 0, 0] \ No newline at end of file +[4, 0, 33, 270, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 3, 5, 83, 8, 5, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 4, 13, 110, 8, 13, 11, 13, 12, 13, 111, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 4, 15, 129, 8, 15, 11, 15, 12, 15, 130, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 3, 17, 153, 8, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 3, 19, 170, 8, 19, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 3, 27, 213, 8, 27, 1, 28, 4, 28, 216, 8, 28, 11, 28, 12, 28, 217, 1, 28, 1, 28, 4, 28, 222, 8, 28, 11, 28, 12, 28, 223, 3, 28, 226, 8, 28, 1, 29, 1, 29, 1, 29, 1, 29, 5, 29, 232, 8, 29, 10, 29, 12, 29, 235, 9, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 5, 29, 242, 8, 29, 10, 29, 12, 29, 245, 9, 29, 1, 29, 3, 29, 248, 8, 29, 1, 30, 1, 30, 5, 30, 252, 8, 30, 10, 30, 12, 30, 255, 9, 30, 1, 31, 4, 31, 258, 8, 31, 11, 31, 12, 31, 259, 1, 31, 1, 31, 1, 32, 1, 32, 1, 33, 4, 33, 267, 8, 33, 11, 33, 12, 33, 268, 0, 0, 34, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 0, 67, 33, 1, 0, 29, 2, 0, 76, 76, 108, 108, 2, 0, 73, 73, 105, 105, 2, 0, 75, 75, 107, 107, 2, 0, 69, 69, 101, 101, 2, 0, 78, 78, 110, 110, 2, 0, 79, 79, 111, 111, 2, 0, 84, 84, 116, 116, 2, 0, 9, 9, 32, 32, 2, 0, 66, 66, 98, 98, 2, 0, 87, 87, 119, 119, 2, 0, 88, 88, 120, 120, 2, 0, 83, 83, 115, 115, 2, 0, 82, 82, 114, 114, 2, 0, 71, 71, 103, 103, 2, 0, 80, 80, 112, 112, 2, 0, 67, 67, 99, 99, 2, 0, 65, 65, 97, 97, 2, 0, 68, 68, 100, 100, 2, 0, 72, 72, 104, 104, 2, 0, 89, 89, 121, 121, 2, 0, 85, 85, 117, 117, 2, 0, 70, 70, 102, 102, 2, 0, 34, 34, 92, 92, 2, 0, 39, 39, 92, 92, 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, 7, 0, 42, 42, 46, 46, 48, 57, 65, 91, 93, 93, 95, 95, 97, 122, 3, 0, 9, 10, 13, 13, 32, 32, 1, 0, 48, 57, 8, 0, 9, 10, 13, 13, 32, 34, 39, 41, 44, 44, 60, 62, 91, 91, 93, 93, 285, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 1, 69, 1, 0, 0, 0, 3, 71, 1, 0, 0, 0, 5, 73, 1, 0, 0, 0, 7, 75, 1, 0, 0, 0, 9, 77, 1, 0, 0, 0, 11, 82, 1, 0, 0, 0, 13, 84, 1, 0, 0, 0, 15, 87, 1, 0, 0, 0, 17, 90, 1, 0, 0, 0, 19, 92, 1, 0, 0, 0, 21, 95, 1, 0, 0, 0, 23, 97, 1, 0, 0, 0, 25, 100, 1, 0, 0, 0, 27, 105, 1, 0, 0, 0, 29, 118, 1, 0, 0, 0, 31, 124, 1, 0, 0, 0, 33, 138, 1, 0, 0, 0, 35, 146, 1, 0, 0, 0, 37, 154, 1, 0, 0, 0, 39, 161, 1, 0, 0, 0, 41, 171, 1, 0, 0, 0, 43, 174, 1, 0, 0, 0, 45, 178, 1, 0, 0, 0, 47, 182, 1, 0, 0, 0, 49, 185, 1, 0, 0, 0, 51, 189, 1, 0, 0, 0, 53, 196, 1, 0, 0, 0, 55, 212, 1, 0, 0, 0, 57, 215, 1, 0, 0, 0, 59, 247, 1, 0, 0, 0, 61, 249, 1, 0, 0, 0, 63, 257, 1, 0, 0, 0, 65, 263, 1, 0, 0, 0, 67, 266, 1, 0, 0, 0, 69, 70, 5, 40, 0, 0, 70, 2, 1, 0, 0, 0, 71, 72, 5, 41, 0, 0, 72, 4, 1, 0, 0, 0, 73, 74, 5, 91, 0, 0, 74, 6, 1, 0, 0, 0, 75, 76, 5, 93, 0, 0, 76, 8, 1, 0, 0, 0, 77, 78, 5, 44, 0, 0, 78, 10, 1, 0, 0, 0, 79, 83, 5, 61, 0, 0, 80, 81, 5, 61, 0, 0, 81, 83, 5, 61, 0, 0, 82, 79, 1, 0, 0, 0, 82, 80, 1, 0, 0, 0, 83, 12, 1, 0, 0, 0, 84, 85, 5, 33, 0, 0, 85, 86, 5, 61, 0, 0, 86, 14, 1, 0, 0, 0, 87, 88, 5, 60, 0, 0, 88, 89, 5, 62, 0, 0, 89, 16, 1, 0, 0, 0, 90, 91, 5, 60, 0, 0, 91, 18, 1, 0, 0, 0, 92, 93, 5, 60, 0, 0, 93, 94, 5, 61, 0, 0, 94, 20, 1, 0, 0, 0, 95, 96, 5, 62, 0, 0, 96, 22, 1, 0, 0, 0, 97, 98, 5, 62, 0, 0, 98, 99, 5, 61, 0, 0, 99, 24, 1, 0, 0, 0, 100, 101, 7, 0, 0, 0, 101, 102, 7, 1, 0, 0, 102, 103, 7, 2, 0, 0, 103, 104, 7, 3, 0, 0, 104, 26, 1, 0, 0, 0, 105, 106, 7, 4, 0, 0, 106, 107, 7, 5, 0, 0, 107, 109, 7, 6, 0, 0, 108, 110, 7, 7, 0, 0, 109, 108, 1, 0, 0, 0, 110, 111, 1, 0, 0, 0, 111, 109, 1, 0, 0, 0, 111, 112, 1, 0, 0, 0, 112, 113, 1, 0, 0, 0, 113, 114, 7, 0, 0, 0, 114, 115, 7, 1, 0, 0, 115, 116, 7, 2, 0, 0, 116, 117, 7, 3, 0, 0, 117, 28, 1, 0, 0, 0, 118, 119, 7, 1, 0, 0, 119, 120, 7, 0, 0, 0, 120, 121, 7, 1, 0, 0, 121, 122, 7, 2, 0, 0, 122, 123, 7, 3, 0, 0, 123, 30, 1, 0, 0, 0, 124, 125, 7, 4, 0, 0, 125, 126, 7, 5, 0, 0, 126, 128, 7, 6, 0, 0, 127, 129, 7, 7, 0, 0, 128, 127, 1, 0, 0, 0, 129, 130, 1, 0, 0, 0, 130, 128, 1, 0, 0, 0, 130, 131, 1, 0, 0, 0, 131, 132, 1, 0, 0, 0, 132, 133, 7, 1, 0, 0, 133, 134, 7, 0, 0, 0, 134, 135, 7, 1, 0, 0, 135, 136, 7, 2, 0, 0, 136, 137, 7, 3, 0, 0, 137, 32, 1, 0, 0, 0, 138, 139, 7, 8, 0, 0, 139, 140, 7, 3, 0, 0, 140, 141, 7, 6, 0, 0, 141, 142, 7, 9, 0, 0, 142, 143, 7, 3, 0, 0, 143, 144, 7, 3, 0, 0, 144, 145, 7, 4, 0, 0, 145, 34, 1, 0, 0, 0, 146, 147, 7, 3, 0, 0, 147, 148, 7, 10, 0, 0, 148, 149, 7, 1, 0, 0, 149, 150, 7, 11, 0, 0, 150, 152, 7, 6, 0, 0, 151, 153, 7, 11, 0, 0, 152, 151, 1, 0, 0, 0, 152, 153, 1, 0, 0, 0, 153, 36, 1, 0, 0, 0, 154, 155, 7, 12, 0, 0, 155, 156, 7, 3, 0, 0, 156, 157, 7, 13, 0, 0, 157, 158, 7, 3, 0, 0, 158, 159, 7, 10, 0, 0, 159, 160, 7, 14, 0, 0, 160, 38, 1, 0, 0, 0, 161, 162, 7, 15, 0, 0, 162, 163, 7, 5, 0, 0, 163, 164, 7, 4, 0, 0, 164, 165, 7, 6, 0, 0, 165, 166, 7, 16, 0, 0, 166, 167, 7, 1, 0, 0, 167, 169, 7, 4, 0, 0, 168, 170, 7, 11, 0, 0, 169, 168, 1, 0, 0, 0, 169, 170, 1, 0, 0, 0, 170, 40, 1, 0, 0, 0, 171, 172, 7, 1, 0, 0, 172, 173, 7, 4, 0, 0, 173, 42, 1, 0, 0, 0, 174, 175, 7, 4, 0, 0, 175, 176, 7, 5, 0, 0, 176, 177, 7, 6, 0, 0, 177, 44, 1, 0, 0, 0, 178, 179, 7, 16, 0, 0, 179, 180, 7, 4, 0, 0, 180, 181, 7, 17, 0, 0, 181, 46, 1, 0, 0, 0, 182, 183, 7, 5, 0, 0, 183, 184, 7, 12, 0, 0, 184, 48, 1, 0, 0, 0, 185, 186, 7, 18, 0, 0, 186, 187, 7, 16, 0, 0, 187, 188, 7, 11, 0, 0, 188, 50, 1, 0, 0, 0, 189, 190, 7, 18, 0, 0, 190, 191, 7, 16, 0, 0, 191, 192, 7, 11, 0, 0, 192, 193, 7, 16, 0, 0, 193, 194, 7, 4, 0, 0, 194, 195, 7, 19, 0, 0, 195, 52, 1, 0, 0, 0, 196, 197, 7, 18, 0, 0, 197, 198, 7, 16, 0, 0, 198, 199, 7, 11, 0, 0, 199, 200, 7, 16, 0, 0, 200, 201, 7, 0, 0, 0, 201, 202, 7, 0, 0, 0, 202, 54, 1, 0, 0, 0, 203, 204, 7, 6, 0, 0, 204, 205, 7, 12, 0, 0, 205, 206, 7, 20, 0, 0, 206, 213, 7, 3, 0, 0, 207, 208, 7, 21, 0, 0, 208, 209, 7, 16, 0, 0, 209, 210, 7, 0, 0, 0, 210, 211, 7, 11, 0, 0, 211, 213, 7, 3, 0, 0, 212, 203, 1, 0, 0, 0, 212, 207, 1, 0, 0, 0, 213, 56, 1, 0, 0, 0, 214, 216, 3, 65, 32, 0, 215, 214, 1, 0, 0, 0, 216, 217, 1, 0, 0, 0, 217, 215, 1, 0, 0, 0, 217, 218, 1, 0, 0, 0, 218, 225, 1, 0, 0, 0, 219, 221, 5, 46, 0, 0, 220, 222, 3, 65, 32, 0, 221, 220, 1, 0, 0, 0, 222, 223, 1, 0, 0, 0, 223, 221, 1, 0, 0, 0, 223, 224, 1, 0, 0, 0, 224, 226, 1, 0, 0, 0, 225, 219, 1, 0, 0, 0, 225, 226, 1, 0, 0, 0, 226, 58, 1, 0, 0, 0, 227, 233, 5, 34, 0, 0, 228, 232, 8, 22, 0, 0, 229, 230, 5, 92, 0, 0, 230, 232, 9, 0, 0, 0, 231, 228, 1, 0, 0, 0, 231, 229, 1, 0, 0, 0, 232, 235, 1, 0, 0, 0, 233, 231, 1, 0, 0, 0, 233, 234, 1, 0, 0, 0, 234, 236, 1, 0, 0, 0, 235, 233, 1, 0, 0, 0, 236, 248, 5, 34, 0, 0, 237, 243, 5, 39, 0, 0, 238, 242, 8, 23, 0, 0, 239, 240, 5, 92, 0, 0, 240, 242, 9, 0, 0, 0, 241, 238, 1, 0, 0, 0, 241, 239, 1, 0, 0, 0, 242, 245, 1, 0, 0, 0, 243, 241, 1, 0, 0, 0, 243, 244, 1, 0, 0, 0, 244, 246, 1, 0, 0, 0, 245, 243, 1, 0, 0, 0, 246, 248, 5, 39, 0, 0, 247, 227, 1, 0, 0, 0, 247, 237, 1, 0, 0, 0, 248, 60, 1, 0, 0, 0, 249, 253, 7, 24, 0, 0, 250, 252, 7, 25, 0, 0, 251, 250, 1, 0, 0, 0, 252, 255, 1, 0, 0, 0, 253, 251, 1, 0, 0, 0, 253, 254, 1, 0, 0, 0, 254, 62, 1, 0, 0, 0, 255, 253, 1, 0, 0, 0, 256, 258, 7, 26, 0, 0, 257, 256, 1, 0, 0, 0, 258, 259, 1, 0, 0, 0, 259, 257, 1, 0, 0, 0, 259, 260, 1, 0, 0, 0, 260, 261, 1, 0, 0, 0, 261, 262, 6, 31, 0, 0, 262, 64, 1, 0, 0, 0, 263, 264, 7, 27, 0, 0, 264, 66, 1, 0, 0, 0, 265, 267, 8, 28, 0, 0, 266, 265, 1, 0, 0, 0, 267, 268, 1, 0, 0, 0, 268, 266, 1, 0, 0, 0, 268, 269, 1, 0, 0, 0, 269, 68, 1, 0, 0, 0, 18, 0, 82, 111, 130, 152, 169, 212, 217, 223, 225, 231, 233, 241, 243, 247, 253, 259, 268, 1, 6, 0, 0] \ No newline at end of file diff --git a/pkg/parser/grammar/FilterQueryLexer.tokens b/pkg/parser/grammar/FilterQueryLexer.tokens index ca38d44fa5..e6c7864740 100644 --- a/pkg/parser/grammar/FilterQueryLexer.tokens +++ b/pkg/parser/grammar/FilterQueryLexer.tokens @@ -25,13 +25,12 @@ OR=24 HAS=25 HASANY=26 HASALL=27 -HASNONE=28 -BOOL=29 -NUMBER=30 -QUOTED_TEXT=31 -KEY=32 -WS=33 -FREETEXT=34 +BOOL=28 +NUMBER=29 +QUOTED_TEXT=30 +KEY=31 +WS=32 +FREETEXT=33 '('=1 ')'=2 '['=3 diff --git a/pkg/parser/grammar/filterquery_lexer.go b/pkg/parser/grammar/filterquery_lexer.go index 82109bf036..e1588f5adb 100644 --- a/pkg/parser/grammar/filterquery_lexer.go +++ b/pkg/parser/grammar/filterquery_lexer.go @@ -50,150 +50,146 @@ func filterquerylexerLexerInit() { "", "LPAREN", "RPAREN", "LBRACK", "RBRACK", "COMMA", "EQUALS", "NOT_EQUALS", "NEQ", "LT", "LE", "GT", "GE", "LIKE", "NOT_LIKE", "ILIKE", "NOT_ILIKE", "BETWEEN", "EXISTS", "REGEXP", "CONTAINS", "IN", "NOT", "AND", "OR", - "HAS", "HASANY", "HASALL", "HASNONE", "BOOL", "NUMBER", "QUOTED_TEXT", - "KEY", "WS", "FREETEXT", + "HAS", "HASANY", "HASALL", "BOOL", "NUMBER", "QUOTED_TEXT", "KEY", "WS", + "FREETEXT", } staticData.RuleNames = []string{ "LPAREN", "RPAREN", "LBRACK", "RBRACK", "COMMA", "EQUALS", "NOT_EQUALS", "NEQ", "LT", "LE", "GT", "GE", "LIKE", "NOT_LIKE", "ILIKE", "NOT_ILIKE", "BETWEEN", "EXISTS", "REGEXP", "CONTAINS", "IN", "NOT", "AND", "OR", - "HAS", "HASANY", "HASALL", "HASNONE", "BOOL", "NUMBER", "QUOTED_TEXT", - "KEY", "WS", "DIGIT", "FREETEXT", + "HAS", "HASANY", "HASALL", "BOOL", "NUMBER", "QUOTED_TEXT", "KEY", "WS", + "DIGIT", "FREETEXT", } staticData.PredictionContextCache = antlr.NewPredictionContextCache() staticData.serializedATN = []int32{ - 4, 0, 34, 280, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, + 4, 0, 33, 270, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, - 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 1, 0, 1, 0, 1, 1, - 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 3, 5, 85, 8, - 5, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, - 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, - 1, 13, 1, 13, 1, 13, 4, 13, 112, 8, 13, 11, 13, 12, 13, 113, 1, 13, 1, - 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, - 1, 15, 1, 15, 1, 15, 4, 15, 131, 8, 15, 11, 15, 12, 15, 132, 1, 15, 1, - 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, - 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 3, 17, 155, 8, - 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, - 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 3, 19, 172, 8, 19, 1, 20, 1, 20, 1, - 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, - 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, - 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, - 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, - 28, 1, 28, 1, 28, 1, 28, 1, 28, 3, 28, 223, 8, 28, 1, 29, 4, 29, 226, 8, - 29, 11, 29, 12, 29, 227, 1, 29, 1, 29, 4, 29, 232, 8, 29, 11, 29, 12, 29, - 233, 3, 29, 236, 8, 29, 1, 30, 1, 30, 1, 30, 1, 30, 5, 30, 242, 8, 30, - 10, 30, 12, 30, 245, 9, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 5, 30, 252, - 8, 30, 10, 30, 12, 30, 255, 9, 30, 1, 30, 3, 30, 258, 8, 30, 1, 31, 1, - 31, 5, 31, 262, 8, 31, 10, 31, 12, 31, 265, 9, 31, 1, 32, 4, 32, 268, 8, - 32, 11, 32, 12, 32, 269, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 4, 34, 277, - 8, 34, 11, 34, 12, 34, 278, 0, 0, 35, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, + 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, + 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 3, 5, 83, 8, 5, 1, 6, 1, 6, + 1, 6, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, + 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, + 1, 13, 4, 13, 110, 8, 13, 11, 13, 12, 13, 111, 1, 13, 1, 13, 1, 13, 1, + 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, + 1, 15, 4, 15, 129, 8, 15, 11, 15, 12, 15, 130, 1, 15, 1, 15, 1, 15, 1, + 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, + 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 3, 17, 153, 8, 17, 1, 18, 1, + 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, + 1, 19, 1, 19, 1, 19, 3, 19, 170, 8, 19, 1, 20, 1, 20, 1, 20, 1, 21, 1, + 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 24, + 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, + 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, + 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 3, 27, 213, 8, 27, 1, 28, 4, 28, 216, + 8, 28, 11, 28, 12, 28, 217, 1, 28, 1, 28, 4, 28, 222, 8, 28, 11, 28, 12, + 28, 223, 3, 28, 226, 8, 28, 1, 29, 1, 29, 1, 29, 1, 29, 5, 29, 232, 8, + 29, 10, 29, 12, 29, 235, 9, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 5, 29, + 242, 8, 29, 10, 29, 12, 29, 245, 9, 29, 1, 29, 3, 29, 248, 8, 29, 1, 30, + 1, 30, 5, 30, 252, 8, 30, 10, 30, 12, 30, 255, 9, 30, 1, 31, 4, 31, 258, + 8, 31, 11, 31, 12, 31, 259, 1, 31, 1, 31, 1, 32, 1, 32, 1, 33, 4, 33, 267, + 8, 33, 11, 33, 12, 33, 268, 0, 0, 34, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, - 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 33, - 67, 0, 69, 34, 1, 0, 29, 2, 0, 76, 76, 108, 108, 2, 0, 73, 73, 105, 105, - 2, 0, 75, 75, 107, 107, 2, 0, 69, 69, 101, 101, 2, 0, 78, 78, 110, 110, - 2, 0, 79, 79, 111, 111, 2, 0, 84, 84, 116, 116, 2, 0, 9, 9, 32, 32, 2, - 0, 66, 66, 98, 98, 2, 0, 87, 87, 119, 119, 2, 0, 88, 88, 120, 120, 2, 0, - 83, 83, 115, 115, 2, 0, 82, 82, 114, 114, 2, 0, 71, 71, 103, 103, 2, 0, - 80, 80, 112, 112, 2, 0, 67, 67, 99, 99, 2, 0, 65, 65, 97, 97, 2, 0, 68, - 68, 100, 100, 2, 0, 72, 72, 104, 104, 2, 0, 89, 89, 121, 121, 2, 0, 85, - 85, 117, 117, 2, 0, 70, 70, 102, 102, 2, 0, 34, 34, 92, 92, 2, 0, 39, 39, - 92, 92, 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, 6, 0, 46, 46, 48, 57, 65, + 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 0, + 67, 33, 1, 0, 29, 2, 0, 76, 76, 108, 108, 2, 0, 73, 73, 105, 105, 2, 0, + 75, 75, 107, 107, 2, 0, 69, 69, 101, 101, 2, 0, 78, 78, 110, 110, 2, 0, + 79, 79, 111, 111, 2, 0, 84, 84, 116, 116, 2, 0, 9, 9, 32, 32, 2, 0, 66, + 66, 98, 98, 2, 0, 87, 87, 119, 119, 2, 0, 88, 88, 120, 120, 2, 0, 83, 83, + 115, 115, 2, 0, 82, 82, 114, 114, 2, 0, 71, 71, 103, 103, 2, 0, 80, 80, + 112, 112, 2, 0, 67, 67, 99, 99, 2, 0, 65, 65, 97, 97, 2, 0, 68, 68, 100, + 100, 2, 0, 72, 72, 104, 104, 2, 0, 89, 89, 121, 121, 2, 0, 85, 85, 117, + 117, 2, 0, 70, 70, 102, 102, 2, 0, 34, 34, 92, 92, 2, 0, 39, 39, 92, 92, + 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, 7, 0, 42, 42, 46, 46, 48, 57, 65, 91, 93, 93, 95, 95, 97, 122, 3, 0, 9, 10, 13, 13, 32, 32, 1, 0, 48, 57, - 7, 0, 9, 10, 13, 13, 32, 34, 39, 41, 60, 62, 91, 91, 93, 93, 295, 0, 1, - 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, - 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, - 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, - 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, - 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, - 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, - 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, - 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, - 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 1, 71, 1, 0, 0, 0, - 3, 73, 1, 0, 0, 0, 5, 75, 1, 0, 0, 0, 7, 77, 1, 0, 0, 0, 9, 79, 1, 0, 0, - 0, 11, 84, 1, 0, 0, 0, 13, 86, 1, 0, 0, 0, 15, 89, 1, 0, 0, 0, 17, 92, - 1, 0, 0, 0, 19, 94, 1, 0, 0, 0, 21, 97, 1, 0, 0, 0, 23, 99, 1, 0, 0, 0, - 25, 102, 1, 0, 0, 0, 27, 107, 1, 0, 0, 0, 29, 120, 1, 0, 0, 0, 31, 126, - 1, 0, 0, 0, 33, 140, 1, 0, 0, 0, 35, 148, 1, 0, 0, 0, 37, 156, 1, 0, 0, - 0, 39, 163, 1, 0, 0, 0, 41, 173, 1, 0, 0, 0, 43, 176, 1, 0, 0, 0, 45, 180, - 1, 0, 0, 0, 47, 184, 1, 0, 0, 0, 49, 187, 1, 0, 0, 0, 51, 191, 1, 0, 0, - 0, 53, 198, 1, 0, 0, 0, 55, 205, 1, 0, 0, 0, 57, 222, 1, 0, 0, 0, 59, 225, - 1, 0, 0, 0, 61, 257, 1, 0, 0, 0, 63, 259, 1, 0, 0, 0, 65, 267, 1, 0, 0, - 0, 67, 273, 1, 0, 0, 0, 69, 276, 1, 0, 0, 0, 71, 72, 5, 40, 0, 0, 72, 2, - 1, 0, 0, 0, 73, 74, 5, 41, 0, 0, 74, 4, 1, 0, 0, 0, 75, 76, 5, 91, 0, 0, - 76, 6, 1, 0, 0, 0, 77, 78, 5, 93, 0, 0, 78, 8, 1, 0, 0, 0, 79, 80, 5, 44, - 0, 0, 80, 10, 1, 0, 0, 0, 81, 85, 5, 61, 0, 0, 82, 83, 5, 61, 0, 0, 83, - 85, 5, 61, 0, 0, 84, 81, 1, 0, 0, 0, 84, 82, 1, 0, 0, 0, 85, 12, 1, 0, - 0, 0, 86, 87, 5, 33, 0, 0, 87, 88, 5, 61, 0, 0, 88, 14, 1, 0, 0, 0, 89, - 90, 5, 60, 0, 0, 90, 91, 5, 62, 0, 0, 91, 16, 1, 0, 0, 0, 92, 93, 5, 60, - 0, 0, 93, 18, 1, 0, 0, 0, 94, 95, 5, 60, 0, 0, 95, 96, 5, 61, 0, 0, 96, - 20, 1, 0, 0, 0, 97, 98, 5, 62, 0, 0, 98, 22, 1, 0, 0, 0, 99, 100, 5, 62, - 0, 0, 100, 101, 5, 61, 0, 0, 101, 24, 1, 0, 0, 0, 102, 103, 7, 0, 0, 0, - 103, 104, 7, 1, 0, 0, 104, 105, 7, 2, 0, 0, 105, 106, 7, 3, 0, 0, 106, - 26, 1, 0, 0, 0, 107, 108, 7, 4, 0, 0, 108, 109, 7, 5, 0, 0, 109, 111, 7, - 6, 0, 0, 110, 112, 7, 7, 0, 0, 111, 110, 1, 0, 0, 0, 112, 113, 1, 0, 0, - 0, 113, 111, 1, 0, 0, 0, 113, 114, 1, 0, 0, 0, 114, 115, 1, 0, 0, 0, 115, - 116, 7, 0, 0, 0, 116, 117, 7, 1, 0, 0, 117, 118, 7, 2, 0, 0, 118, 119, - 7, 3, 0, 0, 119, 28, 1, 0, 0, 0, 120, 121, 7, 1, 0, 0, 121, 122, 7, 0, - 0, 0, 122, 123, 7, 1, 0, 0, 123, 124, 7, 2, 0, 0, 124, 125, 7, 3, 0, 0, - 125, 30, 1, 0, 0, 0, 126, 127, 7, 4, 0, 0, 127, 128, 7, 5, 0, 0, 128, 130, - 7, 6, 0, 0, 129, 131, 7, 7, 0, 0, 130, 129, 1, 0, 0, 0, 131, 132, 1, 0, - 0, 0, 132, 130, 1, 0, 0, 0, 132, 133, 1, 0, 0, 0, 133, 134, 1, 0, 0, 0, - 134, 135, 7, 1, 0, 0, 135, 136, 7, 0, 0, 0, 136, 137, 7, 1, 0, 0, 137, - 138, 7, 2, 0, 0, 138, 139, 7, 3, 0, 0, 139, 32, 1, 0, 0, 0, 140, 141, 7, - 8, 0, 0, 141, 142, 7, 3, 0, 0, 142, 143, 7, 6, 0, 0, 143, 144, 7, 9, 0, - 0, 144, 145, 7, 3, 0, 0, 145, 146, 7, 3, 0, 0, 146, 147, 7, 4, 0, 0, 147, - 34, 1, 0, 0, 0, 148, 149, 7, 3, 0, 0, 149, 150, 7, 10, 0, 0, 150, 151, - 7, 1, 0, 0, 151, 152, 7, 11, 0, 0, 152, 154, 7, 6, 0, 0, 153, 155, 7, 11, - 0, 0, 154, 153, 1, 0, 0, 0, 154, 155, 1, 0, 0, 0, 155, 36, 1, 0, 0, 0, - 156, 157, 7, 12, 0, 0, 157, 158, 7, 3, 0, 0, 158, 159, 7, 13, 0, 0, 159, - 160, 7, 3, 0, 0, 160, 161, 7, 10, 0, 0, 161, 162, 7, 14, 0, 0, 162, 38, - 1, 0, 0, 0, 163, 164, 7, 15, 0, 0, 164, 165, 7, 5, 0, 0, 165, 166, 7, 4, - 0, 0, 166, 167, 7, 6, 0, 0, 167, 168, 7, 16, 0, 0, 168, 169, 7, 1, 0, 0, - 169, 171, 7, 4, 0, 0, 170, 172, 7, 11, 0, 0, 171, 170, 1, 0, 0, 0, 171, - 172, 1, 0, 0, 0, 172, 40, 1, 0, 0, 0, 173, 174, 7, 1, 0, 0, 174, 175, 7, - 4, 0, 0, 175, 42, 1, 0, 0, 0, 176, 177, 7, 4, 0, 0, 177, 178, 7, 5, 0, - 0, 178, 179, 7, 6, 0, 0, 179, 44, 1, 0, 0, 0, 180, 181, 7, 16, 0, 0, 181, - 182, 7, 4, 0, 0, 182, 183, 7, 17, 0, 0, 183, 46, 1, 0, 0, 0, 184, 185, - 7, 5, 0, 0, 185, 186, 7, 12, 0, 0, 186, 48, 1, 0, 0, 0, 187, 188, 7, 18, - 0, 0, 188, 189, 7, 16, 0, 0, 189, 190, 7, 11, 0, 0, 190, 50, 1, 0, 0, 0, - 191, 192, 7, 18, 0, 0, 192, 193, 7, 16, 0, 0, 193, 194, 7, 11, 0, 0, 194, - 195, 7, 16, 0, 0, 195, 196, 7, 4, 0, 0, 196, 197, 7, 19, 0, 0, 197, 52, - 1, 0, 0, 0, 198, 199, 7, 18, 0, 0, 199, 200, 7, 16, 0, 0, 200, 201, 7, - 11, 0, 0, 201, 202, 7, 16, 0, 0, 202, 203, 7, 0, 0, 0, 203, 204, 7, 0, - 0, 0, 204, 54, 1, 0, 0, 0, 205, 206, 7, 18, 0, 0, 206, 207, 7, 16, 0, 0, - 207, 208, 7, 11, 0, 0, 208, 209, 7, 4, 0, 0, 209, 210, 7, 5, 0, 0, 210, - 211, 7, 4, 0, 0, 211, 212, 7, 3, 0, 0, 212, 56, 1, 0, 0, 0, 213, 214, 7, - 6, 0, 0, 214, 215, 7, 12, 0, 0, 215, 216, 7, 20, 0, 0, 216, 223, 7, 3, - 0, 0, 217, 218, 7, 21, 0, 0, 218, 219, 7, 16, 0, 0, 219, 220, 7, 0, 0, - 0, 220, 221, 7, 11, 0, 0, 221, 223, 7, 3, 0, 0, 222, 213, 1, 0, 0, 0, 222, - 217, 1, 0, 0, 0, 223, 58, 1, 0, 0, 0, 224, 226, 3, 67, 33, 0, 225, 224, - 1, 0, 0, 0, 226, 227, 1, 0, 0, 0, 227, 225, 1, 0, 0, 0, 227, 228, 1, 0, - 0, 0, 228, 235, 1, 0, 0, 0, 229, 231, 5, 46, 0, 0, 230, 232, 3, 67, 33, - 0, 231, 230, 1, 0, 0, 0, 232, 233, 1, 0, 0, 0, 233, 231, 1, 0, 0, 0, 233, - 234, 1, 0, 0, 0, 234, 236, 1, 0, 0, 0, 235, 229, 1, 0, 0, 0, 235, 236, - 1, 0, 0, 0, 236, 60, 1, 0, 0, 0, 237, 243, 5, 34, 0, 0, 238, 242, 8, 22, - 0, 0, 239, 240, 5, 92, 0, 0, 240, 242, 9, 0, 0, 0, 241, 238, 1, 0, 0, 0, - 241, 239, 1, 0, 0, 0, 242, 245, 1, 0, 0, 0, 243, 241, 1, 0, 0, 0, 243, - 244, 1, 0, 0, 0, 244, 246, 1, 0, 0, 0, 245, 243, 1, 0, 0, 0, 246, 258, - 5, 34, 0, 0, 247, 253, 5, 39, 0, 0, 248, 252, 8, 23, 0, 0, 249, 250, 5, - 92, 0, 0, 250, 252, 9, 0, 0, 0, 251, 248, 1, 0, 0, 0, 251, 249, 1, 0, 0, - 0, 252, 255, 1, 0, 0, 0, 253, 251, 1, 0, 0, 0, 253, 254, 1, 0, 0, 0, 254, - 256, 1, 0, 0, 0, 255, 253, 1, 0, 0, 0, 256, 258, 5, 39, 0, 0, 257, 237, - 1, 0, 0, 0, 257, 247, 1, 0, 0, 0, 258, 62, 1, 0, 0, 0, 259, 263, 7, 24, - 0, 0, 260, 262, 7, 25, 0, 0, 261, 260, 1, 0, 0, 0, 262, 265, 1, 0, 0, 0, - 263, 261, 1, 0, 0, 0, 263, 264, 1, 0, 0, 0, 264, 64, 1, 0, 0, 0, 265, 263, - 1, 0, 0, 0, 266, 268, 7, 26, 0, 0, 267, 266, 1, 0, 0, 0, 268, 269, 1, 0, - 0, 0, 269, 267, 1, 0, 0, 0, 269, 270, 1, 0, 0, 0, 270, 271, 1, 0, 0, 0, - 271, 272, 6, 32, 0, 0, 272, 66, 1, 0, 0, 0, 273, 274, 7, 27, 0, 0, 274, - 68, 1, 0, 0, 0, 275, 277, 8, 28, 0, 0, 276, 275, 1, 0, 0, 0, 277, 278, - 1, 0, 0, 0, 278, 276, 1, 0, 0, 0, 278, 279, 1, 0, 0, 0, 279, 70, 1, 0, - 0, 0, 18, 0, 84, 113, 132, 154, 171, 222, 227, 233, 235, 241, 243, 251, - 253, 257, 263, 269, 278, 1, 6, 0, 0, + 8, 0, 9, 10, 13, 13, 32, 34, 39, 41, 44, 44, 60, 62, 91, 91, 93, 93, 285, + 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, + 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, + 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, + 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, + 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, + 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, + 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, + 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, + 0, 0, 63, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 1, 69, 1, 0, 0, 0, 3, 71, 1, 0, + 0, 0, 5, 73, 1, 0, 0, 0, 7, 75, 1, 0, 0, 0, 9, 77, 1, 0, 0, 0, 11, 82, + 1, 0, 0, 0, 13, 84, 1, 0, 0, 0, 15, 87, 1, 0, 0, 0, 17, 90, 1, 0, 0, 0, + 19, 92, 1, 0, 0, 0, 21, 95, 1, 0, 0, 0, 23, 97, 1, 0, 0, 0, 25, 100, 1, + 0, 0, 0, 27, 105, 1, 0, 0, 0, 29, 118, 1, 0, 0, 0, 31, 124, 1, 0, 0, 0, + 33, 138, 1, 0, 0, 0, 35, 146, 1, 0, 0, 0, 37, 154, 1, 0, 0, 0, 39, 161, + 1, 0, 0, 0, 41, 171, 1, 0, 0, 0, 43, 174, 1, 0, 0, 0, 45, 178, 1, 0, 0, + 0, 47, 182, 1, 0, 0, 0, 49, 185, 1, 0, 0, 0, 51, 189, 1, 0, 0, 0, 53, 196, + 1, 0, 0, 0, 55, 212, 1, 0, 0, 0, 57, 215, 1, 0, 0, 0, 59, 247, 1, 0, 0, + 0, 61, 249, 1, 0, 0, 0, 63, 257, 1, 0, 0, 0, 65, 263, 1, 0, 0, 0, 67, 266, + 1, 0, 0, 0, 69, 70, 5, 40, 0, 0, 70, 2, 1, 0, 0, 0, 71, 72, 5, 41, 0, 0, + 72, 4, 1, 0, 0, 0, 73, 74, 5, 91, 0, 0, 74, 6, 1, 0, 0, 0, 75, 76, 5, 93, + 0, 0, 76, 8, 1, 0, 0, 0, 77, 78, 5, 44, 0, 0, 78, 10, 1, 0, 0, 0, 79, 83, + 5, 61, 0, 0, 80, 81, 5, 61, 0, 0, 81, 83, 5, 61, 0, 0, 82, 79, 1, 0, 0, + 0, 82, 80, 1, 0, 0, 0, 83, 12, 1, 0, 0, 0, 84, 85, 5, 33, 0, 0, 85, 86, + 5, 61, 0, 0, 86, 14, 1, 0, 0, 0, 87, 88, 5, 60, 0, 0, 88, 89, 5, 62, 0, + 0, 89, 16, 1, 0, 0, 0, 90, 91, 5, 60, 0, 0, 91, 18, 1, 0, 0, 0, 92, 93, + 5, 60, 0, 0, 93, 94, 5, 61, 0, 0, 94, 20, 1, 0, 0, 0, 95, 96, 5, 62, 0, + 0, 96, 22, 1, 0, 0, 0, 97, 98, 5, 62, 0, 0, 98, 99, 5, 61, 0, 0, 99, 24, + 1, 0, 0, 0, 100, 101, 7, 0, 0, 0, 101, 102, 7, 1, 0, 0, 102, 103, 7, 2, + 0, 0, 103, 104, 7, 3, 0, 0, 104, 26, 1, 0, 0, 0, 105, 106, 7, 4, 0, 0, + 106, 107, 7, 5, 0, 0, 107, 109, 7, 6, 0, 0, 108, 110, 7, 7, 0, 0, 109, + 108, 1, 0, 0, 0, 110, 111, 1, 0, 0, 0, 111, 109, 1, 0, 0, 0, 111, 112, + 1, 0, 0, 0, 112, 113, 1, 0, 0, 0, 113, 114, 7, 0, 0, 0, 114, 115, 7, 1, + 0, 0, 115, 116, 7, 2, 0, 0, 116, 117, 7, 3, 0, 0, 117, 28, 1, 0, 0, 0, + 118, 119, 7, 1, 0, 0, 119, 120, 7, 0, 0, 0, 120, 121, 7, 1, 0, 0, 121, + 122, 7, 2, 0, 0, 122, 123, 7, 3, 0, 0, 123, 30, 1, 0, 0, 0, 124, 125, 7, + 4, 0, 0, 125, 126, 7, 5, 0, 0, 126, 128, 7, 6, 0, 0, 127, 129, 7, 7, 0, + 0, 128, 127, 1, 0, 0, 0, 129, 130, 1, 0, 0, 0, 130, 128, 1, 0, 0, 0, 130, + 131, 1, 0, 0, 0, 131, 132, 1, 0, 0, 0, 132, 133, 7, 1, 0, 0, 133, 134, + 7, 0, 0, 0, 134, 135, 7, 1, 0, 0, 135, 136, 7, 2, 0, 0, 136, 137, 7, 3, + 0, 0, 137, 32, 1, 0, 0, 0, 138, 139, 7, 8, 0, 0, 139, 140, 7, 3, 0, 0, + 140, 141, 7, 6, 0, 0, 141, 142, 7, 9, 0, 0, 142, 143, 7, 3, 0, 0, 143, + 144, 7, 3, 0, 0, 144, 145, 7, 4, 0, 0, 145, 34, 1, 0, 0, 0, 146, 147, 7, + 3, 0, 0, 147, 148, 7, 10, 0, 0, 148, 149, 7, 1, 0, 0, 149, 150, 7, 11, + 0, 0, 150, 152, 7, 6, 0, 0, 151, 153, 7, 11, 0, 0, 152, 151, 1, 0, 0, 0, + 152, 153, 1, 0, 0, 0, 153, 36, 1, 0, 0, 0, 154, 155, 7, 12, 0, 0, 155, + 156, 7, 3, 0, 0, 156, 157, 7, 13, 0, 0, 157, 158, 7, 3, 0, 0, 158, 159, + 7, 10, 0, 0, 159, 160, 7, 14, 0, 0, 160, 38, 1, 0, 0, 0, 161, 162, 7, 15, + 0, 0, 162, 163, 7, 5, 0, 0, 163, 164, 7, 4, 0, 0, 164, 165, 7, 6, 0, 0, + 165, 166, 7, 16, 0, 0, 166, 167, 7, 1, 0, 0, 167, 169, 7, 4, 0, 0, 168, + 170, 7, 11, 0, 0, 169, 168, 1, 0, 0, 0, 169, 170, 1, 0, 0, 0, 170, 40, + 1, 0, 0, 0, 171, 172, 7, 1, 0, 0, 172, 173, 7, 4, 0, 0, 173, 42, 1, 0, + 0, 0, 174, 175, 7, 4, 0, 0, 175, 176, 7, 5, 0, 0, 176, 177, 7, 6, 0, 0, + 177, 44, 1, 0, 0, 0, 178, 179, 7, 16, 0, 0, 179, 180, 7, 4, 0, 0, 180, + 181, 7, 17, 0, 0, 181, 46, 1, 0, 0, 0, 182, 183, 7, 5, 0, 0, 183, 184, + 7, 12, 0, 0, 184, 48, 1, 0, 0, 0, 185, 186, 7, 18, 0, 0, 186, 187, 7, 16, + 0, 0, 187, 188, 7, 11, 0, 0, 188, 50, 1, 0, 0, 0, 189, 190, 7, 18, 0, 0, + 190, 191, 7, 16, 0, 0, 191, 192, 7, 11, 0, 0, 192, 193, 7, 16, 0, 0, 193, + 194, 7, 4, 0, 0, 194, 195, 7, 19, 0, 0, 195, 52, 1, 0, 0, 0, 196, 197, + 7, 18, 0, 0, 197, 198, 7, 16, 0, 0, 198, 199, 7, 11, 0, 0, 199, 200, 7, + 16, 0, 0, 200, 201, 7, 0, 0, 0, 201, 202, 7, 0, 0, 0, 202, 54, 1, 0, 0, + 0, 203, 204, 7, 6, 0, 0, 204, 205, 7, 12, 0, 0, 205, 206, 7, 20, 0, 0, + 206, 213, 7, 3, 0, 0, 207, 208, 7, 21, 0, 0, 208, 209, 7, 16, 0, 0, 209, + 210, 7, 0, 0, 0, 210, 211, 7, 11, 0, 0, 211, 213, 7, 3, 0, 0, 212, 203, + 1, 0, 0, 0, 212, 207, 1, 0, 0, 0, 213, 56, 1, 0, 0, 0, 214, 216, 3, 65, + 32, 0, 215, 214, 1, 0, 0, 0, 216, 217, 1, 0, 0, 0, 217, 215, 1, 0, 0, 0, + 217, 218, 1, 0, 0, 0, 218, 225, 1, 0, 0, 0, 219, 221, 5, 46, 0, 0, 220, + 222, 3, 65, 32, 0, 221, 220, 1, 0, 0, 0, 222, 223, 1, 0, 0, 0, 223, 221, + 1, 0, 0, 0, 223, 224, 1, 0, 0, 0, 224, 226, 1, 0, 0, 0, 225, 219, 1, 0, + 0, 0, 225, 226, 1, 0, 0, 0, 226, 58, 1, 0, 0, 0, 227, 233, 5, 34, 0, 0, + 228, 232, 8, 22, 0, 0, 229, 230, 5, 92, 0, 0, 230, 232, 9, 0, 0, 0, 231, + 228, 1, 0, 0, 0, 231, 229, 1, 0, 0, 0, 232, 235, 1, 0, 0, 0, 233, 231, + 1, 0, 0, 0, 233, 234, 1, 0, 0, 0, 234, 236, 1, 0, 0, 0, 235, 233, 1, 0, + 0, 0, 236, 248, 5, 34, 0, 0, 237, 243, 5, 39, 0, 0, 238, 242, 8, 23, 0, + 0, 239, 240, 5, 92, 0, 0, 240, 242, 9, 0, 0, 0, 241, 238, 1, 0, 0, 0, 241, + 239, 1, 0, 0, 0, 242, 245, 1, 0, 0, 0, 243, 241, 1, 0, 0, 0, 243, 244, + 1, 0, 0, 0, 244, 246, 1, 0, 0, 0, 245, 243, 1, 0, 0, 0, 246, 248, 5, 39, + 0, 0, 247, 227, 1, 0, 0, 0, 247, 237, 1, 0, 0, 0, 248, 60, 1, 0, 0, 0, + 249, 253, 7, 24, 0, 0, 250, 252, 7, 25, 0, 0, 251, 250, 1, 0, 0, 0, 252, + 255, 1, 0, 0, 0, 253, 251, 1, 0, 0, 0, 253, 254, 1, 0, 0, 0, 254, 62, 1, + 0, 0, 0, 255, 253, 1, 0, 0, 0, 256, 258, 7, 26, 0, 0, 257, 256, 1, 0, 0, + 0, 258, 259, 1, 0, 0, 0, 259, 257, 1, 0, 0, 0, 259, 260, 1, 0, 0, 0, 260, + 261, 1, 0, 0, 0, 261, 262, 6, 31, 0, 0, 262, 64, 1, 0, 0, 0, 263, 264, + 7, 27, 0, 0, 264, 66, 1, 0, 0, 0, 265, 267, 8, 28, 0, 0, 266, 265, 1, 0, + 0, 0, 267, 268, 1, 0, 0, 0, 268, 266, 1, 0, 0, 0, 268, 269, 1, 0, 0, 0, + 269, 68, 1, 0, 0, 0, 18, 0, 82, 111, 130, 152, 169, 212, 217, 223, 225, + 231, 233, 241, 243, 247, 253, 259, 268, 1, 6, 0, 0, } deserializer := antlr.NewATNDeserializer(nil) staticData.atn = deserializer.Deserialize(staticData.serializedATN) @@ -261,11 +257,10 @@ const ( FilterQueryLexerHAS = 25 FilterQueryLexerHASANY = 26 FilterQueryLexerHASALL = 27 - FilterQueryLexerHASNONE = 28 - FilterQueryLexerBOOL = 29 - FilterQueryLexerNUMBER = 30 - FilterQueryLexerQUOTED_TEXT = 31 - FilterQueryLexerKEY = 32 - FilterQueryLexerWS = 33 - FilterQueryLexerFREETEXT = 34 + FilterQueryLexerBOOL = 28 + FilterQueryLexerNUMBER = 29 + FilterQueryLexerQUOTED_TEXT = 30 + FilterQueryLexerKEY = 31 + FilterQueryLexerWS = 32 + FilterQueryLexerFREETEXT = 33 ) diff --git a/pkg/parser/grammar/filterquery_parser.go b/pkg/parser/grammar/filterquery_parser.go index dbbb547e0a..aa8285b63c 100644 --- a/pkg/parser/grammar/filterquery_parser.go +++ b/pkg/parser/grammar/filterquery_parser.go @@ -40,8 +40,8 @@ func filterqueryParserInit() { "", "LPAREN", "RPAREN", "LBRACK", "RBRACK", "COMMA", "EQUALS", "NOT_EQUALS", "NEQ", "LT", "LE", "GT", "GE", "LIKE", "NOT_LIKE", "ILIKE", "NOT_ILIKE", "BETWEEN", "EXISTS", "REGEXP", "CONTAINS", "IN", "NOT", "AND", "OR", - "HAS", "HASANY", "HASALL", "HASNONE", "BOOL", "NUMBER", "QUOTED_TEXT", - "KEY", "WS", "FREETEXT", + "HAS", "HASANY", "HASALL", "BOOL", "NUMBER", "QUOTED_TEXT", "KEY", "WS", + "FREETEXT", } staticData.RuleNames = []string{ "query", "expression", "orExpression", "andExpression", "unaryExpression", @@ -51,7 +51,7 @@ func filterqueryParserInit() { } staticData.PredictionContextCache = antlr.NewPredictionContextCache() staticData.serializedATN = []int32{ - 4, 1, 34, 212, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, + 4, 1, 33, 212, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 5, 2, 43, @@ -72,7 +72,7 @@ func filterqueryParserInit() { 13, 1, 13, 1, 13, 3, 13, 202, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 0, 0, 17, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 0, 6, 1, 0, 7, 8, 2, 0, 13, 13, 15, 15, 2, - 0, 14, 14, 16, 16, 2, 0, 31, 31, 34, 34, 1, 0, 25, 28, 1, 0, 29, 32, 225, + 0, 14, 14, 16, 16, 2, 0, 30, 30, 33, 33, 1, 0, 25, 27, 1, 0, 28, 31, 225, 0, 34, 1, 0, 0, 0, 2, 37, 1, 0, 0, 0, 4, 39, 1, 0, 0, 0, 6, 47, 1, 0, 0, 0, 8, 57, 1, 0, 0, 0, 10, 69, 1, 0, 0, 0, 12, 147, 1, 0, 0, 0, 14, 159, 1, 0, 0, 0, 16, 173, 1, 0, 0, 0, 18, 175, 1, 0, 0, 0, 20, 183, 1, 0, 0, @@ -140,7 +140,7 @@ func filterqueryParserInit() { 201, 198, 1, 0, 0, 0, 201, 199, 1, 0, 0, 0, 201, 200, 1, 0, 0, 0, 202, 27, 1, 0, 0, 0, 203, 204, 5, 3, 0, 0, 204, 205, 3, 18, 9, 0, 205, 206, 5, 4, 0, 0, 206, 29, 1, 0, 0, 0, 207, 208, 7, 5, 0, 0, 208, 31, 1, 0, 0, - 0, 209, 210, 5, 32, 0, 0, 210, 33, 1, 0, 0, 0, 11, 44, 51, 53, 57, 69, + 0, 209, 210, 5, 31, 0, 0, 210, 33, 1, 0, 0, 0, 11, 44, 51, 53, 57, 69, 147, 159, 173, 180, 195, 201, } deserializer := antlr.NewATNDeserializer(nil) @@ -207,13 +207,12 @@ const ( FilterQueryParserHAS = 25 FilterQueryParserHASANY = 26 FilterQueryParserHASALL = 27 - FilterQueryParserHASNONE = 28 - FilterQueryParserBOOL = 29 - FilterQueryParserNUMBER = 30 - FilterQueryParserQUOTED_TEXT = 31 - FilterQueryParserKEY = 32 - FilterQueryParserWS = 33 - FilterQueryParserFREETEXT = 34 + FilterQueryParserBOOL = 28 + FilterQueryParserNUMBER = 29 + FilterQueryParserQUOTED_TEXT = 30 + FilterQueryParserKEY = 31 + FilterQueryParserWS = 32 + FilterQueryParserFREETEXT = 33 ) // FilterQueryParser rules. @@ -803,7 +802,7 @@ func (p *FilterQueryParser) AndExpression() (localctx IAndExpressionContext) { } _la = p.GetTokenStream().LA(1) - for (int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&24138219522) != 0 { + for (int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&12058624002) != 0 { p.SetState(51) p.GetErrorHandler().Sync(p) if p.HasError() { @@ -825,7 +824,7 @@ func (p *FilterQueryParser) AndExpression() (localctx IAndExpressionContext) { p.UnaryExpression() } - case FilterQueryParserLPAREN, FilterQueryParserNOT, FilterQueryParserHAS, FilterQueryParserHASANY, FilterQueryParserHASALL, FilterQueryParserHASNONE, FilterQueryParserQUOTED_TEXT, FilterQueryParserKEY, FilterQueryParserFREETEXT: + case FilterQueryParserLPAREN, FilterQueryParserNOT, FilterQueryParserHAS, FilterQueryParserHASANY, FilterQueryParserHASALL, FilterQueryParserQUOTED_TEXT, FilterQueryParserKEY, FilterQueryParserFREETEXT: { p.SetState(50) p.UnaryExpression() @@ -2653,7 +2652,6 @@ type IFunctionCallContext interface { HAS() antlr.TerminalNode HASANY() antlr.TerminalNode HASALL() antlr.TerminalNode - HASNONE() antlr.TerminalNode // IsFunctionCallContext differentiates from other interfaces. IsFunctionCallContext() @@ -2727,10 +2725,6 @@ func (s *FunctionCallContext) HASALL() antlr.TerminalNode { return s.GetToken(FilterQueryParserHASALL, 0) } -func (s *FunctionCallContext) HASNONE() antlr.TerminalNode { - return s.GetToken(FilterQueryParserHASNONE, 0) -} - func (s *FunctionCallContext) GetRuleContext() antlr.RuleContext { return s } @@ -2771,7 +2765,7 @@ func (p *FilterQueryParser) FunctionCall() (localctx IFunctionCallContext) { p.SetState(185) _la = p.GetTokenStream().LA(1) - if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&503316480) != 0) { + if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&234881024) != 0) { p.GetErrorHandler().RecoverInline(p) } else { p.GetErrorHandler().ReportMatch(p) @@ -3411,7 +3405,7 @@ func (p *FilterQueryParser) Value() (localctx IValueContext) { p.SetState(207) _la = p.GetTokenStream().LA(1) - if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&8053063680) != 0) { + if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&4026531840) != 0) { p.GetErrorHandler().RecoverInline(p) } else { p.GetErrorHandler().ReportMatch(p) diff --git a/pkg/parser/grammar/query_to_keys.go b/pkg/parser/grammar/query_to_keys.go new file mode 100644 index 0000000000..d0e2268f3d --- /dev/null +++ b/pkg/parser/grammar/query_to_keys.go @@ -0,0 +1,48 @@ +package parser + +import ( + "github.com/SigNoz/signoz/pkg/types/telemetrytypes" + "github.com/antlr4-go/antlr/v4" +) + +// QueryStringToKeysSelectors converts a query string to a list of field key selectors +// +// e.g. "service.name="query-service" AND http.status_code=200 AND resource.k8s.namespace.name="application"" -> []*telemetrytypes.FieldKeySelector{ +// { +// Name: "service.name", +// FieldContext: telemetrytypes.FieldContextUnspecified, +// FieldDataType: telemetrytypes.FieldDataTypeUnspecified, +// }, +// { +// Name: "http.status_code", +// FieldContext: telemetrytypes.FieldContextUnspecified, +// FieldDataType: telemetrytypes.FieldDataTypeUnspecified, +// }, +// { +// Name: "resource.k8s.namespace.name", +// FieldContext: telemetrytypes.FieldContextResource, +// FieldDataType: telemetrytypes.FieldDataTypeUnspecified, +// }, +// } +func QueryStringToKeysSelectors(query string) ([]*telemetrytypes.FieldKeySelector, error) { + lexer := NewFilterQueryLexer(antlr.NewInputStream(query)) + keys := []*telemetrytypes.FieldKeySelector{} + for { + tok := lexer.NextToken() + if tok.GetTokenType() == antlr.TokenEOF { + break + } + + if tok.GetTokenType() == FilterQueryLexerKEY { + key := telemetrytypes.GetFieldKeyFromKeyText(tok.GetText()) + keys = append(keys, &telemetrytypes.FieldKeySelector{ + Name: key.Name, + Signal: key.Signal, + FieldContext: key.FieldContext, + FieldDataType: key.FieldDataType, + }) + } + } + + return keys, nil +} diff --git a/pkg/parser/grammar/query_to_keys_test.go b/pkg/parser/grammar/query_to_keys_test.go new file mode 100644 index 0000000000..795401e1c4 --- /dev/null +++ b/pkg/parser/grammar/query_to_keys_test.go @@ -0,0 +1,101 @@ +package parser + +import ( + "testing" + + "github.com/SigNoz/signoz/pkg/types/telemetrytypes" +) + +func TestQueryToKeys(t *testing.T) { + + testCases := []struct { + query string + expectedKeys []telemetrytypes.FieldKeySelector + }{ + { + query: `service.name="redis"`, + expectedKeys: []telemetrytypes.FieldKeySelector{ + { + Name: "service.name", + Signal: telemetrytypes.SignalUnspecified, + FieldContext: telemetrytypes.FieldContextUnspecified, + FieldDataType: telemetrytypes.FieldDataTypeUnspecified, + }, + }, + }, + { + query: `resource.service.name="redis"`, + expectedKeys: []telemetrytypes.FieldKeySelector{ + { + Name: "service.name", + Signal: telemetrytypes.SignalUnspecified, + FieldContext: telemetrytypes.FieldContextResource, + FieldDataType: telemetrytypes.FieldDataTypeUnspecified, + }, + }, + }, + { + query: `service.name="redis" AND http.status_code=200`, + expectedKeys: []telemetrytypes.FieldKeySelector{ + { + Name: "service.name", + Signal: telemetrytypes.SignalUnspecified, + FieldContext: telemetrytypes.FieldContextUnspecified, + FieldDataType: telemetrytypes.FieldDataTypeUnspecified, + }, + { + Name: "http.status_code", + Signal: telemetrytypes.SignalUnspecified, + FieldContext: telemetrytypes.FieldContextUnspecified, + FieldDataType: telemetrytypes.FieldDataTypeUnspecified, + }, + }, + }, + { + query: `has(payload.user_ids, 123)`, + expectedKeys: []telemetrytypes.FieldKeySelector{ + { + Name: "payload.user_ids", + Signal: telemetrytypes.SignalUnspecified, + FieldContext: telemetrytypes.FieldContextUnspecified, + FieldDataType: telemetrytypes.FieldDataTypeUnspecified, + }, + }, + }, + { + query: `body.user_ids[*] = 123`, + expectedKeys: []telemetrytypes.FieldKeySelector{ + { + Name: "body.user_ids[*]", + Signal: telemetrytypes.SignalUnspecified, + FieldContext: telemetrytypes.FieldContextUnspecified, + FieldDataType: telemetrytypes.FieldDataTypeUnspecified, + }, + }, + }, + } + + for _, testCase := range testCases { + keys, err := QueryStringToKeysSelectors(testCase.query) + if err != nil { + t.Fatalf("Error: %v", err) + } + if len(keys) != len(testCase.expectedKeys) { + t.Fatalf("Expected %d keys, got %d", len(testCase.expectedKeys), len(keys)) + } + for i, key := range keys { + if key.Name != testCase.expectedKeys[i].Name { + t.Fatalf("Expected key %v, got %v", testCase.expectedKeys[i], key) + } + if key.Signal != testCase.expectedKeys[i].Signal { + t.Fatalf("Expected signal %v, got %v", testCase.expectedKeys[i].Signal, key.Signal) + } + if key.FieldContext != testCase.expectedKeys[i].FieldContext { + t.Fatalf("Expected field context %v, got %v", testCase.expectedKeys[i].FieldContext, key.FieldContext) + } + if key.FieldDataType != testCase.expectedKeys[i].FieldDataType { + t.Fatalf("Expected field data type %v, got %v", testCase.expectedKeys[i].FieldDataType, key.FieldDataType) + } + } + } +} diff --git a/pkg/parser/grammar/where_clause_visitor.go b/pkg/parser/grammar/where_clause_visitor.go new file mode 100644 index 0000000000..3145f946c6 --- /dev/null +++ b/pkg/parser/grammar/where_clause_visitor.go @@ -0,0 +1,587 @@ +package parser + +import ( + "context" + "fmt" + "strconv" + "strings" + + "github.com/SigNoz/signoz/pkg/errors" + "github.com/SigNoz/signoz/pkg/telemetrylogs" + qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5" + "github.com/SigNoz/signoz/pkg/types/telemetrytypes" + "github.com/antlr4-go/antlr/v4" + + sqlbuilder "github.com/huandu/go-sqlbuilder" +) + +// WhereClauseVisitor implements the FilterQueryVisitor interface +// to convert the parsed filter expressions into ClickHouse WHERE clause +type WhereClauseVisitor struct { + conditionBuilder qbtypes.ConditionBuilder + warnings []error + fieldKeys map[string][]telemetrytypes.TelemetryFieldKey + errors []error + builder *sqlbuilder.SelectBuilder + fullTextColumn telemetrytypes.TelemetryFieldKey +} + +// NewWhereClauseVisitor creates a new WhereClauseVisitor +func NewWhereClauseVisitor( + conditionBuilder qbtypes.ConditionBuilder, + fieldKeys map[string][]telemetrytypes.TelemetryFieldKey, + builder *sqlbuilder.SelectBuilder, + fullTextColumn telemetrytypes.TelemetryFieldKey, +) *WhereClauseVisitor { + return &WhereClauseVisitor{ + conditionBuilder: conditionBuilder, + fieldKeys: fieldKeys, + builder: builder, + fullTextColumn: fullTextColumn, + } +} + +type SyntaxError struct { + line, column int + msg string +} + +func (e *SyntaxError) Error() string { + return fmt.Sprintf("line %d:%d %s", e.line, e.column, e.msg) +} + +// ErrorListener is a custom error listener to capture syntax errors +type ErrorListener struct { + *antlr.DefaultErrorListener + Errors []error +} + +// NewErrorListener creates a new error listener +func NewErrorListener() *ErrorListener { + return &ErrorListener{ + DefaultErrorListener: antlr.NewDefaultErrorListener(), + Errors: []error{}, + } +} + +// SyntaxError captures syntax errors during parsing +func (l *ErrorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol any, line, column int, msg string, e antlr.RecognitionException) { + l.Errors = append(l.Errors, &SyntaxError{line: line, column: column, msg: msg}) +} + +// PrepareWhereClause generates a ClickHouse compatible WHERE clause from the filter query +func PrepareWhereClause( + query string, + fieldKeys map[string][]telemetrytypes.TelemetryFieldKey, + conditionBuilder qbtypes.ConditionBuilder, + fullTextColumn telemetrytypes.TelemetryFieldKey, +) (string, []any, []error, error) { + // Setup the ANTLR parsing pipeline + input := antlr.NewInputStream(query) + lexer := NewFilterQueryLexer(input) + + sb := sqlbuilder.NewSelectBuilder() + + visitor := NewWhereClauseVisitor(conditionBuilder, fieldKeys, sb, fullTextColumn) + + // Set up error handling + lexerErrorListener := NewErrorListener() + lexer.RemoveErrorListeners() + lexer.AddErrorListener(lexerErrorListener) + + tokens := antlr.NewCommonTokenStream(lexer, 0) + parserErrorListener := NewErrorListener() + parser := NewFilterQueryParser(tokens) + parser.RemoveErrorListeners() + parser.AddErrorListener(parserErrorListener) + + // Parse the query + tree := parser.Query() + + // Handle syntax errors + if len(parserErrorListener.Errors) > 0 { + combinedErrors := errors.Newf( + errors.TypeInvalidInput, + errors.CodeInvalidInput, + "found %d syntax errors while parsing the search expression: %v", + len(parserErrorListener.Errors), + parserErrorListener.Errors, + ) + return "", nil, nil, combinedErrors + } + + // Visit the parse tree with our ClickHouse visitor + cond := visitor.Visit(tree).(string) + + if len(visitor.errors) > 0 { + // combine all errors into a single error + combinedErrors := errors.Newf( + errors.TypeInvalidInput, + errors.CodeInvalidInput, + "found %d errors while parsing the search expression: %v", + len(visitor.errors), + visitor.errors, + ) + return "", nil, nil, combinedErrors + } + + whereClause, args := visitor.builder.Where(cond).BuildWithFlavor(sqlbuilder.ClickHouse) + + return whereClause, args, visitor.warnings, nil +} + +// Visit dispatches to the specific visit method based on node type +func (v *WhereClauseVisitor) Visit(tree antlr.ParseTree) any { + // Handle nil nodes to prevent panic + if tree == nil { + return "" + } + + switch t := tree.(type) { + case *QueryContext: + return v.VisitQuery(t) + case *ExpressionContext: + return v.VisitExpression(t) + case *OrExpressionContext: + return v.VisitOrExpression(t) + case *AndExpressionContext: + return v.VisitAndExpression(t) + case *UnaryExpressionContext: + return v.VisitUnaryExpression(t) + case *PrimaryContext: + return v.VisitPrimary(t) + case *ComparisonContext: + return v.VisitComparison(t) + case *InClauseContext: + return v.VisitInClause(t) + case *NotInClauseContext: + return v.VisitNotInClause(t) + case *ValueListContext: + return v.VisitValueList(t) + case *FullTextContext: + return v.VisitFullText(t) + case *FunctionCallContext: + return v.VisitFunctionCall(t) + case *FunctionParamListContext: + return v.VisitFunctionParamList(t) + case *FunctionParamContext: + return v.VisitFunctionParam(t) + case *ArrayContext: + return v.VisitArray(t) + case *ValueContext: + return v.VisitValue(t) + case *KeyContext: + return v.VisitKey(t) + default: + return "" + } +} + +func (v *WhereClauseVisitor) VisitQuery(ctx *QueryContext) any { + + return v.Visit(ctx.Expression()) +} + +// VisitExpression passes through to the orExpression +func (v *WhereClauseVisitor) VisitExpression(ctx *ExpressionContext) any { + return v.Visit(ctx.OrExpression()) +} + +// VisitOrExpression handles OR expressions +func (v *WhereClauseVisitor) VisitOrExpression(ctx *OrExpressionContext) any { + andExpressions := ctx.AllAndExpression() + + andExpressionConditions := make([]string, len(andExpressions)) + for i, expr := range andExpressions { + andExpressionConditions[i] = v.Visit(expr).(string) + } + + if len(andExpressionConditions) == 1 { + return andExpressionConditions[0] + } + + return v.builder.Or(andExpressionConditions...) +} + +// VisitAndExpression handles AND expressions +func (v *WhereClauseVisitor) VisitAndExpression(ctx *AndExpressionContext) any { + unaryExpressions := ctx.AllUnaryExpression() + + unaryExpressionConditions := make([]string, len(unaryExpressions)) + for i, expr := range unaryExpressions { + unaryExpressionConditions[i] = v.Visit(expr).(string) + } + + if len(unaryExpressionConditions) == 1 { + return unaryExpressionConditions[0] + } + + return v.builder.And(unaryExpressionConditions...) +} + +// VisitUnaryExpression handles NOT expressions +func (v *WhereClauseVisitor) VisitUnaryExpression(ctx *UnaryExpressionContext) any { + result := v.Visit(ctx.Primary()).(string) + + // Check if this is a NOT expression + if ctx.NOT() != nil { + return fmt.Sprintf("NOT (%s)", result) + } + + return result +} + +// VisitPrimary handles grouped expressions, comparisons, function calls, and full-text search +func (v *WhereClauseVisitor) VisitPrimary(ctx *PrimaryContext) any { + if ctx.OrExpression() != nil { + // This is a parenthesized expression + return fmt.Sprintf("(%s)", v.Visit(ctx.OrExpression()).(string)) + } else if ctx.Comparison() != nil { + return v.Visit(ctx.Comparison()) + } else if ctx.FunctionCall() != nil { + return v.Visit(ctx.FunctionCall()) + } else if ctx.FullText() != nil { + return v.Visit(ctx.FullText()) + } + + // Handle standalone key as a full text search term + if ctx.GetChildCount() == 1 { + child := ctx.GetChild(0) + if keyCtx, ok := child.(*KeyContext); ok { + // create a full text search condition on the body field + keyText := keyCtx.GetText() + cond, err := v.conditionBuilder.GetCondition(context.Background(), &v.fullTextColumn, qbtypes.FilterOperatorRegexp, keyText, v.builder) + if err != nil { + return "" + } + return cond + } + } + + return "" // Should not happen with valid input +} + +// VisitComparison handles all comparison operators +func (v *WhereClauseVisitor) VisitComparison(ctx *ComparisonContext) any { + keys := v.Visit(ctx.Key()).([]telemetrytypes.TelemetryFieldKey) + + // Handle EXISTS specially + if ctx.EXISTS() != nil { + op := qbtypes.FilterOperatorExists + if ctx.NOT() != nil { + op = qbtypes.FilterOperatorNotExists + } + var conds []string + for _, key := range keys { + condition, err := v.conditionBuilder.GetCondition(context.Background(), &key, op, nil, v.builder) + if err != nil { + return "" + } + conds = append(conds, condition) + } + return v.builder.Or(conds...) + } + + // Handle IN clause + if ctx.InClause() != nil || ctx.NotInClause() != nil { + values := v.Visit(ctx.InClause()).([]any) + op := qbtypes.FilterOperatorIn + if ctx.NotInClause() != nil { + op = qbtypes.FilterOperatorNotIn + } + var conds []string + for _, key := range keys { + condition, err := v.conditionBuilder.GetCondition(context.Background(), &key, op, values, v.builder) + if err != nil { + return "" + } + conds = append(conds, condition) + } + return v.builder.Or(conds...) + } + + // Handle BETWEEN + if ctx.BETWEEN() != nil { + op := qbtypes.FilterOperatorBetween + if ctx.NOT() != nil { + op = qbtypes.FilterOperatorNotBetween + } + + values := ctx.AllValue() + if len(values) != 2 { + return "" + } + + value1 := v.Visit(values[0]) + value2 := v.Visit(values[1]) + + var conds []string + for _, key := range keys { + condition, err := v.conditionBuilder.GetCondition(context.Background(), &key, op, []any{value1, value2}, v.builder) + if err != nil { + return "" + } + conds = append(conds, condition) + } + return v.builder.Or(conds...) + } + + // Get all values for operations that need them + values := ctx.AllValue() + if len(values) > 0 { + value := v.Visit(values[0]) + + var op qbtypes.FilterOperator + + // Handle each type of comparison + if ctx.EQUALS() != nil { + op = qbtypes.FilterOperatorEqual + } else if ctx.NOT_EQUALS() != nil || ctx.NEQ() != nil { + op = qbtypes.FilterOperatorNotEqual + } else if ctx.LT() != nil { + op = qbtypes.FilterOperatorLessThan + } else if ctx.LE() != nil { + op = qbtypes.FilterOperatorLessThanOrEq + } else if ctx.GT() != nil { + op = qbtypes.FilterOperatorGreaterThan + } else if ctx.GE() != nil { + op = qbtypes.FilterOperatorGreaterThanOrEq + } else if ctx.LIKE() != nil { + op = qbtypes.FilterOperatorLike + } else if ctx.ILIKE() != nil { + op = qbtypes.FilterOperatorLike + } else if ctx.NOT_LIKE() != nil { + op = qbtypes.FilterOperatorNotLike + } else if ctx.NOT_ILIKE() != nil { + op = qbtypes.FilterOperatorNotLike + } else if ctx.REGEXP() != nil { + op = qbtypes.FilterOperatorRegexp + } else if ctx.NOT() != nil && ctx.REGEXP() != nil { + op = qbtypes.FilterOperatorNotRegexp + } else if ctx.CONTAINS() != nil { + op = qbtypes.FilterOperatorContains + } else if ctx.NOT() != nil && ctx.CONTAINS() != nil { + op = qbtypes.FilterOperatorNotContains + } + + var conds []string + for _, key := range keys { + condition, err := v.conditionBuilder.GetCondition(context.Background(), &key, op, value, v.builder) + if err != nil { + return "" + } + conds = append(conds, condition) + } + return v.builder.Or(conds...) + } + + return "" // Should not happen with valid input +} + +// VisitInClause handles IN expressions +func (v *WhereClauseVisitor) VisitInClause(ctx *InClauseContext) any { + return v.Visit(ctx.ValueList()) +} + +// VisitNotInClause handles NOT IN expressions +func (v *WhereClauseVisitor) VisitNotInClause(ctx *NotInClauseContext) any { + return v.Visit(ctx.ValueList()) +} + +// VisitValueList handles comma-separated value lists +func (v *WhereClauseVisitor) VisitValueList(ctx *ValueListContext) any { + values := ctx.AllValue() + + parts := []any{} + for _, val := range values { + parts = append(parts, v.Visit(val)) + } + + return parts +} + +// VisitFullText handles standalone quoted strings for full-text search +func (v *WhereClauseVisitor) VisitFullText(ctx *FullTextContext) any { + // remove quotes from the quotedText + quotedText := strings.Trim(ctx.QUOTED_TEXT().GetText(), "\"'") + cond, err := v.conditionBuilder.GetCondition(context.Background(), &v.fullTextColumn, qbtypes.FilterOperatorRegexp, quotedText, v.builder) + if err != nil { + return "" + } + return cond +} + +// VisitFunctionCall handles function calls like has(), hasAny(), etc. +func (v *WhereClauseVisitor) VisitFunctionCall(ctx *FunctionCallContext) any { + // Get function name based on which token is present + var functionName string + if ctx.HAS() != nil { + functionName = "has" + } else if ctx.HASANY() != nil { + functionName = "hasAny" + } else if ctx.HASALL() != nil { + functionName = "hasAll" + } else { + // Default fallback + v.errors = append(v.errors, errors.Newf( + errors.TypeInvalidInput, + errors.CodeInvalidInput, + "unknown function `%s`", + ctx.GetText(), + )) + return "" + } + params := v.Visit(ctx.FunctionParamList()).([]any) + + if len(params) < 2 { + v.errors = append(v.errors, errors.Newf( + errors.TypeInvalidInput, + errors.CodeInvalidInput, + "function `%s` expects key and value parameters", + functionName, + )) + return "" + } + + keys, ok := params[0].([]telemetrytypes.TelemetryFieldKey) + if !ok { + v.errors = append(v.errors, errors.Newf( + errors.TypeInvalidInput, + errors.CodeInvalidInput, + "function `%s` expects key parameter to be a field key", + functionName, + )) + return "" + } + value := params[1:] + var conds []string + for _, key := range keys { + var fieldName string + + if strings.HasPrefix(key.Name, telemetrylogs.BodyJSONStringSearchPrefix) { + fieldName, _ = telemetrylogs.GetBodyJSONKey(context.Background(), &key, qbtypes.FilterOperatorUnknown, value) + } else { + fieldName, _ = v.conditionBuilder.GetTableFieldName(context.Background(), &key) + } + + var cond string + // Map our functions to ClickHouse equivalents + switch functionName { + case "has": + cond = fmt.Sprintf("has(%s, %s)", fieldName, v.builder.Var(value[0])) + case "hasAny": + cond = fmt.Sprintf("hasAny(%s, %s)", fieldName, v.builder.Var(value)) + case "hasAll": + cond = fmt.Sprintf("hasAll(%s, %s)", fieldName, v.builder.Var(value)) + } + conds = append(conds, cond) + } + + return v.builder.Or(conds...) +} + +// VisitFunctionParamList handles the parameter list for function calls +func (v *WhereClauseVisitor) VisitFunctionParamList(ctx *FunctionParamListContext) any { + params := ctx.AllFunctionParam() + parts := make([]any, len(params)) + + for i, param := range params { + parts[i] = v.Visit(param) + } + + return parts +} + +// VisitFunctionParam handles individual parameters in function calls +func (v *WhereClauseVisitor) VisitFunctionParam(ctx *FunctionParamContext) any { + if ctx.Key() != nil { + return v.Visit(ctx.Key()) + } else if ctx.Value() != nil { + return v.Visit(ctx.Value()) + } else if ctx.Array() != nil { + return v.Visit(ctx.Array()) + } + + return "" // Should not happen with valid input +} + +// VisitArray handles array literals +func (v *WhereClauseVisitor) VisitArray(ctx *ArrayContext) any { + return v.Visit(ctx.ValueList()) +} + +// VisitValue handles literal values: strings, numbers, booleans +func (v *WhereClauseVisitor) VisitValue(ctx *ValueContext) any { + if ctx.QUOTED_TEXT() != nil { + txt := ctx.QUOTED_TEXT().GetText() + // trim quotes and return the value + return strings.Trim(txt, "\"'") + } else if ctx.NUMBER() != nil { + number, err := strconv.ParseFloat(ctx.NUMBER().GetText(), 64) + if err != nil { + v.errors = append(v.errors, errors.Newf( + errors.TypeInvalidInput, + errors.CodeInvalidInput, + "failed to parse number %s", + ctx.NUMBER().GetText(), + )) + return "" + } + return number + } else if ctx.BOOL() != nil { + // Convert to ClickHouse boolean literal + boolText := strings.ToLower(ctx.BOOL().GetText()) + return boolText == "true" + } else if ctx.KEY() != nil { + // Why do we have a KEY context here? + // When the user writes an expression like `service.name=redis` + // The `redis` part is a VALUE context but parsed as a KEY token + // so we return the text as is + return ctx.KEY().GetText() + } + + return "" // Should not happen with valid input +} + +// VisitKey handles field/column references +func (v *WhereClauseVisitor) VisitKey(ctx *KeyContext) any { + + fieldKey := telemetrytypes.GetFieldKeyFromKeyText(ctx.KEY().GetText()) + + keyName := strings.TrimPrefix(fieldKey.Name, telemetrylogs.BodyJSONStringSearchPrefix) + + fieldKeysForName := v.fieldKeys[keyName] + + // for the body json search, we need to add search on the body field even + // if there is a field with the same name as attribute/resource attribute + // Since it will ORed with the fieldKeysForName, it will not result empty + // when either of them have values + if strings.HasPrefix(fieldKey.Name, telemetrylogs.BodyJSONStringSearchPrefix) { + fieldKeysForName = append(fieldKeysForName, fieldKey) + } + + // TODO(srikanthccv): do we want to return an error here? + // should we infer the type and auto-magically build a key for expression? + if len(fieldKeysForName) == 0 { + v.errors = append(v.errors, errors.Newf( + errors.TypeInvalidInput, + errors.CodeInvalidInput, + "key `%s` not found", + fieldKey.Name, + )) + } + + if len(fieldKeysForName) > 1 { + // this is warning state, we must have a unambiguous key + v.warnings = append(v.warnings, errors.Newf( + errors.TypeInvalidInput, + errors.CodeInvalidInput, + "key `%s` is ambiguous, found %d different combinations of field context and data type: %v", + fieldKey.Name, + len(fieldKeysForName), + fieldKeysForName, + )) + } + + return fieldKeysForName +} diff --git a/pkg/parser/grammar/where_clause_visitor_test.go b/pkg/parser/grammar/where_clause_visitor_test.go new file mode 100644 index 0000000000..1faf1f2adc --- /dev/null +++ b/pkg/parser/grammar/where_clause_visitor_test.go @@ -0,0 +1,638 @@ +package parser + +import ( + "reflect" + "strings" + "testing" + + "github.com/SigNoz/signoz/pkg/telemetrylogs" + "github.com/SigNoz/signoz/pkg/telemetrytraces" + "github.com/SigNoz/signoz/pkg/types/telemetrytypes" +) + +func TestConvertToClickHouseLogsQuery(t *testing.T) { + cases := []struct { + name string + fieldKeys map[string][]telemetrytypes.TelemetryFieldKey + query string + expectedSearchString string + expectedSearchArgs []any + }{ + { + name: "test-simple-service-name-filter", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "service.name": { + { + Name: "service.name", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextResource, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "service.name=redis", + expectedSearchString: "WHERE (resources_string['service.name'] = ?)", + expectedSearchArgs: []any{"redis"}, + }, + { + name: "test-simple-service-name-filter-with-materialised-column", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "service.name": { + { + Name: "service.name", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextResource, + FieldDataType: telemetrytypes.FieldDataTypeString, + Materialized: true, + }, + }, + }, + query: "service.name=redis", + expectedSearchString: "WHERE (resource_string_service$$name = ?)", + expectedSearchArgs: []any{"redis"}, + }, + { + name: "http-status-code-multiple-data-types", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "http.status_code": { + { + Name: "http.status_code", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeFloat64, + }, + { + Name: "http.status_code", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "http.status_code=200", + expectedSearchString: "WHERE (attributes_number['http.status_code'] = ? OR toFloat64OrNull(attributes_string['http.status_code']) = ?)", + expectedSearchArgs: []any{float64(200), float64(200)}, + }, + { + name: "http-status-code-multiple-data-types-between-operator", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "http.status_code": { + { + Name: "http.status_code", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeFloat64, + }, + { + Name: "http.status_code", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "http.status_code between 200 and 300", + expectedSearchString: "WHERE (attributes_number['http.status_code'] BETWEEN ? AND ? OR toFloat64OrNull(attributes_string['http.status_code']) BETWEEN ? AND ?)", + expectedSearchArgs: []any{float64(200), float64(300), float64(200), float64(300)}, + }, + { + name: "response-body-multiple-data-types-string-contains", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "response.body": { + { + Name: "response.body", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeFloat64, + }, + { + Name: "response.body", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "response.body contains error", + expectedSearchString: "WHERE (LOWER(toString(attributes_number['response.body'])) LIKE LOWER(?) OR LOWER(attributes_string['response.body']) LIKE LOWER(?))", + expectedSearchArgs: []any{"%error%", "%error%"}, + }, + { + name: "search-on-top-level-key", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "severity_text": { + { + Name: "severity_text", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextLog, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "severity_text=error", + expectedSearchString: "WHERE (severity_text = ?)", + expectedSearchArgs: []any{"error"}, + }, + { + name: "search-on-top-level-key-conflict-with-attribute", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "severity_text": { + { + Name: "severity_text", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextLog, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + { + Name: "severity_text", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "severity_text=error", + expectedSearchString: "WHERE (severity_text = ? OR attributes_string['severity_text'] = ?)", + expectedSearchArgs: []any{"error", "error"}, + }, + { + name: "collision-with-attribute-field-and-resource-attribute", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "k8s.namespace.name": { + { + Name: "k8s.namespace.name", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextResource, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + { + Name: "k8s.namespace.name", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "k8s.namespace.name=test", + expectedSearchString: "WHERE (resources_string['k8s.namespace.name'] = ? OR attributes_string['k8s.namespace.name'] = ?)", + expectedSearchArgs: []any{"test", "test"}, + }, + { + name: "collision-with-attribute-field-and-resource-attribute-materialised-column", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "k8s.namespace.name": { + { + Name: "k8s.namespace.name", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextResource, + FieldDataType: telemetrytypes.FieldDataTypeString, + Materialized: true, + }, + { + Name: "k8s.namespace.name", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "k8s.namespace.name=test", + expectedSearchString: "WHERE (resource_string_k8s$$namespace$$name = ? OR attributes_string['k8s.namespace.name'] = ?)", + expectedSearchArgs: []any{"test", "test"}, + }, + { + name: "boolean-collision-with-attribute-field-and-data-type-boolean", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "did_user_login": { + { + Name: "did_user_login", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeBool, + }, + { + Name: "did_user_login", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "did_user_login=true", + expectedSearchString: "WHERE (attributes_bool['did_user_login'] = ? OR attributes_string['did_user_login'] = ?)", + expectedSearchArgs: []any{true, "true"}, + }, + { + name: "regexp-search", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "k8s.namespace.name": { + { + Name: "k8s.namespace.name", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + "service.name": { + { + Name: "service.name", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextResource, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "k8s.namespace.name REGEXP 'test' OR service.name='redis'", + expectedSearchString: "WHERE (((match(attributes_string['k8s.namespace.name'], ?))) OR (resources_string['service.name'] = ?))", + expectedSearchArgs: []any{"test", "redis"}, + }, + { + name: "full-text-search-multiple-words", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, + query: "waiting for response", + expectedSearchString: "WHERE ((match(body, ?)) AND (match(body, ?)) AND (match(body, ?)))", + expectedSearchArgs: []any{"waiting", "for", "response"}, + }, + { + name: "full-text-search-with-phrase-search", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, + query: `"waiting for response"`, + expectedSearchString: "WHERE (match(body, ?))", + expectedSearchArgs: []any{"waiting for response"}, + }, + { + name: "full-text-search-with-word-and-not-word", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, + query: "error NOT buggy_app", + expectedSearchString: "WHERE ((match(body, ?)) AND NOT ((match(body, ?))))", + expectedSearchArgs: []any{"error", "buggy_app"}, + }, + { + name: "full-text-search-with-word-and-not-word-and-not-word", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, + query: "error NOT buggy_app NOT redis", + expectedSearchString: "WHERE ((match(body, ?)) AND NOT ((match(body, ?))) AND NOT ((match(body, ?))))", + expectedSearchArgs: []any{"error", "buggy_app", "redis"}, + }, + { + name: "full-text-search-with-word-and-not-word-and-not-word-tricky", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, + query: "error NOT buggy_app OR redis", + expectedSearchString: "WHERE (((match(body, ?)) AND NOT ((match(body, ?)))) OR (match(body, ?)))", + expectedSearchArgs: []any{"error", "buggy_app", "redis"}, + }, + { + name: "has-function", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "service.name": { + { + Name: "service.name", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextResource, + }, + }, + "payload.user_ids": { + { + Name: "payload.user_ids", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextAttribute, + }, + }, + }, + query: "has(service.name, 'redis')", + expectedSearchString: "WHERE (has(resources_string['service.name'], ?))", + expectedSearchArgs: []any{"redis"}, + }, + { + name: "has-from-list-of-values", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, + query: "has(body.payload.user_ids[*], 'u1292')", + expectedSearchString: "WHERE (has(JSONExtract(JSON_QUERY(body, '$.payload.user_ids[*]'), 'Array(String)'), ?))", + expectedSearchArgs: []any{"u1292"}, + }, + { + name: "body-json-search-that-also-has-attribute-with-same-name", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "http.status_code": { + { + Name: "http.status_code", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeFloat64, + Materialized: true, + }, + }, + }, + query: "body.http.status_code=200", + expectedSearchString: "WHERE (attribute_number_http$$status_code = ? OR JSONExtract(JSON_VALUE(body, '$.http.status_code'), 'Float64') = ?)", + expectedSearchArgs: []any{float64(200), float64(200)}, + }, + } + + for _, c := range cases { + t.Logf("running test %s", c.name) + chQuery, chQueryArgs, _, err := PrepareWhereClause(c.query, c.fieldKeys, telemetrylogs.NewConditionBuilder(), telemetrytypes.TelemetryFieldKey{ + Name: "body", + Signal: telemetrytypes.SignalLogs, + FieldContext: telemetrytypes.FieldContextLog, + FieldDataType: telemetrytypes.FieldDataTypeString, + }) + if err != nil { + t.Errorf("Error converting query to ClickHouse: %v", err) + } + if chQuery != c.expectedSearchString { + t.Errorf("Expected %s, got %s", c.expectedSearchString, chQuery) + } + if !reflect.DeepEqual(chQueryArgs, c.expectedSearchArgs) { + for i, arg := range chQueryArgs { + t.Logf("Expected %v with type %T, got %v with type %T\n", c.expectedSearchArgs[i], c.expectedSearchArgs[i], arg, arg) + } + t.Errorf("Expected %v, got %v", c.expectedSearchArgs, chQueryArgs) + } + } +} + +func TestConvertToClickHouseSpansQuery(t *testing.T) { + cases := []struct { + name string + fieldKeys map[string][]telemetrytypes.TelemetryFieldKey + query string + expectedSearchString string + expectedSearchArgs []any + }{ + { + name: "test-simple-service-name-filter", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "service.name": { + { + Name: "service.name", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextResource, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "service.name=redis", + expectedSearchString: "WHERE (resources_string['service.name'] = ?)", + expectedSearchArgs: []any{"redis"}, + }, + { + name: "test-simple-service-name-filter-with-materialised-column", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "service.name": { + { + Name: "service.name", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextResource, + FieldDataType: telemetrytypes.FieldDataTypeString, + Materialized: true, + }, + }, + }, + query: "service.name=redis", + expectedSearchString: "WHERE (resource_string_service$$name = ?)", + expectedSearchArgs: []any{"redis"}, + }, + { + name: "http-status-code-multiple-data-types", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "http.status_code": { + { + Name: "http.status_code", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeFloat64, + }, + { + Name: "http.status_code", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "http.status_code=200", + expectedSearchString: "WHERE (attributes_number['http.status_code'] = ? OR toFloat64OrNull(attributes_string['http.status_code']) = ?)", + expectedSearchArgs: []any{float64(200), float64(200)}, + }, + { + name: "http-status-code-multiple-data-types-between-operator", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "http.status_code": { + { + Name: "http.status_code", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeFloat64, + }, + { + Name: "http.status_code", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "http.status_code between 200 and 300", + expectedSearchString: "WHERE (attributes_number['http.status_code'] BETWEEN ? AND ? OR toFloat64OrNull(attributes_string['http.status_code']) BETWEEN ? AND ?)", + expectedSearchArgs: []any{float64(200), float64(300), float64(200), float64(300)}, + }, + { + name: "response-body-multiple-data-types-string-contains", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "response.body": { + { + Name: "response.body", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeFloat64, + }, + { + Name: "response.body", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "response.body contains error", + expectedSearchString: "WHERE (LOWER(toString(attributes_number['response.body'])) LIKE LOWER(?) OR LOWER(attributes_string['response.body']) LIKE LOWER(?))", + expectedSearchArgs: []any{"%error%", "%error%"}, + }, + { + name: "collision-with-attribute-field-and-resource-attribute", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "k8s.namespace.name": { + { + Name: "k8s.namespace.name", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextResource, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + { + Name: "k8s.namespace.name", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "k8s.namespace.name=test", + expectedSearchString: "WHERE (resources_string['k8s.namespace.name'] = ? OR attributes_string['k8s.namespace.name'] = ?)", + expectedSearchArgs: []any{"test", "test"}, + }, + { + name: "collision-with-attribute-field-and-resource-attribute-materialised-column", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "k8s.namespace.name": { + { + Name: "k8s.namespace.name", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextResource, + FieldDataType: telemetrytypes.FieldDataTypeString, + Materialized: true, + }, + { + Name: "k8s.namespace.name", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "k8s.namespace.name=test", + expectedSearchString: "WHERE (resource_string_k8s$$namespace$$name = ? OR attributes_string['k8s.namespace.name'] = ?)", + expectedSearchArgs: []any{"test", "test"}, + }, + { + name: "boolean-collision-with-attribute-field-and-data-type-boolean", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "did_user_login": { + { + Name: "did_user_login", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeBool, + }, + { + Name: "did_user_login", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "did_user_login=true", + expectedSearchString: "WHERE (attributes_bool['did_user_login'] = ? OR attributes_string['did_user_login'] = ?)", + expectedSearchArgs: []any{true, "true"}, + }, + { + name: "regexp-search", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{ + "k8s.namespace.name": { + { + Name: "k8s.namespace.name", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextAttribute, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + "service.name": { + { + Name: "service.name", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextResource, + FieldDataType: telemetrytypes.FieldDataTypeString, + }, + }, + }, + query: "k8s.namespace.name REGEXP 'test' OR service.name='redis'", + expectedSearchString: "WHERE (((match(attributes_string['k8s.namespace.name'], ?))) OR (resources_string['service.name'] = ?))", + expectedSearchArgs: []any{"test", "redis"}, + }, + } + + for _, c := range cases { + chQuery, chQueryArgs, _, err := PrepareWhereClause(c.query, c.fieldKeys, telemetrytraces.NewConditionBuilder(), telemetrytypes.TelemetryFieldKey{ + Name: "dummy", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextSpan, + FieldDataType: telemetrytypes.FieldDataTypeString, + }) + if err != nil { + t.Errorf("Error converting query to ClickHouse: %v", err) + } + if chQuery != c.expectedSearchString { + t.Errorf("Expected %s, got %s", c.expectedSearchString, chQuery) + } + if !reflect.DeepEqual(chQueryArgs, c.expectedSearchArgs) { + for i, arg := range chQueryArgs { + t.Logf("Expected %v with type %T, got %v with type %T\n", c.expectedSearchArgs[i], c.expectedSearchArgs[i], arg, arg) + } + t.Errorf("Expected %v, got %v", c.expectedSearchArgs, chQueryArgs) + } + } +} + +func TestConvertToClickHouseSpansQueryWithErrors(t *testing.T) { + cases := []struct { + name string + fieldKeys map[string][]telemetrytypes.TelemetryFieldKey + query string + expectedSearchString string + expectedSearchArgs []any + expectedErrorSubString string + expectedWarnings []error + }{ + { + name: "has-function-with-multiple-values", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, + query: "key.that.does.not.exist = 'redis'", + expectedSearchString: "", + expectedSearchArgs: []any{}, + expectedErrorSubString: "key `key.that.does.not.exist` not found", + expectedWarnings: []error{}, + }, + { + name: "unknown-function", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, + query: "unknown.function()", + expectedSearchString: "", + expectedSearchArgs: []any{}, + expectedErrorSubString: "expecting {'(', NOT, HAS, HASANY, HASALL, QUOTED_TEXT, KEY, FREETEXT}", + expectedWarnings: []error{}, + }, + { + name: "has-function-not-enough-params", + fieldKeys: map[string][]telemetrytypes.TelemetryFieldKey{}, + query: "has(key.that.does.not.exist)", + expectedSearchString: "", + expectedSearchArgs: []any{}, + expectedErrorSubString: "function `has` expects key and value parameters", + expectedWarnings: []error{}, + }, + } + + for _, c := range cases { + _, _, warnings, err := PrepareWhereClause(c.query, c.fieldKeys, telemetrytraces.NewConditionBuilder(), telemetrytypes.TelemetryFieldKey{ + Name: "dummy", + Signal: telemetrytypes.SignalTraces, + FieldContext: telemetrytypes.FieldContextSpan, + FieldDataType: telemetrytypes.FieldDataTypeString, + }) + if err != nil { + if !strings.Contains(err.Error(), c.expectedErrorSubString) { + t.Errorf("Expected error %v, got %v", c.expectedErrorSubString, err) + } + } + + if len(warnings) != len(c.expectedWarnings) { + t.Errorf("Expected %d warnings, got %d", len(c.expectedWarnings), len(warnings)) + } + for i, warning := range warnings { + if warning.Error() != c.expectedWarnings[i].Error() { + t.Errorf("Expected warning %d to be %v, got %v", i, c.expectedWarnings[i], warning) + } + } + } +} diff --git a/pkg/telemetrylogs/condition_builder.go b/pkg/telemetrylogs/condition_builder.go index 762f3af508..63cb5b64d8 100644 --- a/pkg/telemetrylogs/condition_builder.go +++ b/pkg/telemetrylogs/condition_builder.go @@ -3,10 +3,13 @@ package telemetrylogs import ( "context" "fmt" + "strconv" + "strings" schema "github.com/SigNoz/signoz-otel-collector/cmd/signozschemamigrator/schema_migrator" qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5" "github.com/SigNoz/signoz/pkg/types/telemetrytypes" + "github.com/SigNoz/signoz/pkg/valuer" "github.com/huandu/go-sqlbuilder" ) @@ -81,9 +84,13 @@ func (c *conditionBuilder) GetColumn(ctx context.Context, key *telemetrytypes.Te case telemetrytypes.FieldDataTypeBool: return logsV2Columns["attributes_bool"], nil } - case telemetrytypes.FieldContextLog: + case telemetrytypes.FieldContextLog, telemetrytypes.FieldContextUnspecified: col, ok := logsV2Columns[key.Name] if !ok { + // check if the key has body JSON search + if strings.HasPrefix(key.Name, BodyJSONStringSearchPrefix) { + return logsV2Columns["body"], nil + } return nil, qbtypes.ErrColumnNotFound } return col, nil @@ -137,6 +144,83 @@ func (c *conditionBuilder) GetTableFieldName(ctx context.Context, key *telemetry return column.Name, nil } +func parseStrValue(valueStr string, operator qbtypes.FilterOperator) (telemetrytypes.FieldDataType, any) { + + valueType := telemetrytypes.FieldDataTypeString + + // return the value as is for the following operators + // as they are always string + if operator == qbtypes.FilterOperatorContains || operator == qbtypes.FilterOperatorNotContains || + operator == qbtypes.FilterOperatorRegexp || operator == qbtypes.FilterOperatorNotRegexp || + operator == qbtypes.FilterOperatorLike || operator == qbtypes.FilterOperatorNotLike || + operator == qbtypes.FilterOperatorILike || operator == qbtypes.FilterOperatorNotILike { + return valueType, valueStr + } + + var err error + var parsedValue any + if parsedValue, err = strconv.ParseBool(valueStr); err == nil { + valueType = telemetrytypes.FieldDataTypeBool + } else if parsedValue, err = strconv.ParseInt(valueStr, 10, 64); err == nil { + valueType = telemetrytypes.FieldDataTypeInt64 + } else if parsedValue, err = strconv.ParseFloat(valueStr, 64); err == nil { + valueType = telemetrytypes.FieldDataTypeFloat64 + } else { + parsedValue = valueStr + valueType = telemetrytypes.FieldDataTypeString + } + + return valueType, parsedValue +} + +func inferDataType(value any, operator qbtypes.FilterOperator, key *telemetrytypes.TelemetryFieldKey) (telemetrytypes.FieldDataType, any) { + // check if the value is a int, float, string, bool + valueType := telemetrytypes.FieldDataTypeUnspecified + switch v := value.(type) { + case []any: + // take the first element and infer the type + if len(v) > 0 { + valueType, _ = inferDataType(v[0], operator, key) + } + return valueType, v + case uint8, uint16, uint32, uint64, int, int8, int16, int32, int64: + valueType = telemetrytypes.FieldDataTypeInt64 + case float32, float64: + valueType = telemetrytypes.FieldDataTypeFloat64 + case string: + valueType, value = parseStrValue(v, operator) + case bool: + valueType = telemetrytypes.FieldDataTypeBool + } + + // check if it is array + if strings.HasSuffix(key.Name, "[*]") { + valueType = telemetrytypes.FieldDataType{String: valuer.NewString(fmt.Sprintf("[]%s", valueType.StringValue()))} + } + + return valueType, value +} + +func GetBodyJSONKey(_ context.Context, key *telemetrytypes.TelemetryFieldKey, operator qbtypes.FilterOperator, value any) (string, any) { + + dataType, value := inferDataType(value, operator, key) + + // all body json keys are of the form body. + path := strings.Join(strings.Split(key.Name, ".")[1:], ".") + + // for array types, we need to extract the value from the JSON_QUERY + if dataType == telemetrytypes.FieldDataTypeArrayInt64 || + dataType == telemetrytypes.FieldDataTypeArrayFloat64 || + dataType == telemetrytypes.FieldDataTypeArrayString || + dataType == telemetrytypes.FieldDataTypeArrayBool || + dataType == telemetrytypes.FieldDataTypeArrayNumber { + return fmt.Sprintf("JSONExtract(JSON_QUERY(body, '$.%s'), '%s')", path, dataType.CHDataType()), value + } + + // for all other types, we need to extract the value from the JSON_VALUE + return fmt.Sprintf("JSONExtract(JSON_VALUE(body, '$.%s'), '%s')", path, dataType.CHDataType()), value +} + func (c *conditionBuilder) GetCondition( ctx context.Context, key *telemetrytypes.TelemetryFieldKey, @@ -154,6 +238,10 @@ func (c *conditionBuilder) GetCondition( return "", err } + if strings.HasPrefix(key.Name, BodyJSONStringSearchPrefix) { + tblFieldName, value = GetBodyJSONKey(ctx, key, operator, value) + } + tblFieldName, value = telemetrytypes.DataTypeCollisionHandledFieldName(key, value, tblFieldName) // regular operators diff --git a/pkg/telemetrylogs/condition_builder_test.go b/pkg/telemetrylogs/condition_builder_test.go index 1ad643ab62..45049a6c06 100644 --- a/pkg/telemetrylogs/condition_builder_test.go +++ b/pkg/telemetrylogs/condition_builder_test.go @@ -618,3 +618,194 @@ func TestGetConditionMultiple(t *testing.T) { }) } } + +func TestGetConditionJSONBodySearch(t *testing.T) { + ctx := context.Background() + conditionBuilder := NewConditionBuilder() + + testCases := []struct { + name string + key telemetrytypes.TelemetryFieldKey + operator qbtypes.FilterOperator + value any + expectedSQL string + expectedError error + }{ + { + name: "Equal operator - int64", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.status_code", + }, + operator: qbtypes.FilterOperatorEqual, + value: 200, + expectedSQL: "JSONExtract(JSON_VALUE(body, '$.http.status_code'), 'Int64') = ?", + expectedError: nil, + }, + { + name: "Equal operator - float64", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.duration_ms", + }, + operator: qbtypes.FilterOperatorEqual, + value: 405.5, + expectedSQL: "JSONExtract(JSON_VALUE(body, '$.duration_ms'), 'Float64') = ?", + expectedError: nil, + }, + { + name: "Equal operator - string", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.method", + }, + operator: qbtypes.FilterOperatorEqual, + value: "GET", + expectedSQL: "JSONExtract(JSON_VALUE(body, '$.http.method'), 'String') = ?", + expectedError: nil, + }, + { + name: "Equal operator - bool", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.success", + }, + operator: qbtypes.FilterOperatorEqual, + value: true, + expectedSQL: "JSONExtract(JSON_VALUE(body, '$.http.success'), 'Bool') = ?", + expectedError: nil, + }, + { + name: "Exists operator", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.status_code", + }, + operator: qbtypes.FilterOperatorExists, + value: nil, + expectedSQL: "JSONExtract(JSON_VALUE(body, '$.http.status_code'), 'String') <> ?", + expectedError: nil, + }, + { + name: "Not Exists operator", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.status_code", + }, + operator: qbtypes.FilterOperatorNotExists, + value: nil, + expectedSQL: "JSONExtract(JSON_VALUE(body, '$.http.status_code'), 'String') = ?", + expectedError: nil, + }, + { + name: "Greater than operator - string", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.status_code", + }, + operator: qbtypes.FilterOperatorGreaterThan, + value: "200", + expectedSQL: "JSONExtract(JSON_VALUE(body, '$.http.status_code'), 'Int64') > ?", + expectedError: nil, + }, + { + name: "Greater than operator - int64", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.status_code", + }, + operator: qbtypes.FilterOperatorGreaterThan, + value: 200, + expectedSQL: "JSONExtract(JSON_VALUE(body, '$.http.status_code'), 'Int64') > ?", + expectedError: nil, + }, + { + name: "Less than operator - string", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.status_code", + }, + operator: qbtypes.FilterOperatorLessThan, + value: "300", + expectedSQL: "JSONExtract(JSON_VALUE(body, '$.http.status_code'), 'Int64') < ?", + expectedError: nil, + }, + { + name: "Less than operator - int64", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.status_code", + }, + operator: qbtypes.FilterOperatorLessThan, + value: 300, + expectedSQL: "JSONExtract(JSON_VALUE(body, '$.http.status_code'), 'Int64') < ?", + expectedError: nil, + }, + { + name: "Contains operator - string", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.status_code", + }, + operator: qbtypes.FilterOperatorContains, + value: "200", + expectedSQL: "LOWER(JSONExtract(JSON_VALUE(body, '$.http.status_code'), 'String')) LIKE LOWER(?)", + expectedError: nil, + }, + { + name: "Not Contains operator - string", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.status_code", + }, + operator: qbtypes.FilterOperatorNotContains, + value: "200", + expectedSQL: "LOWER(JSONExtract(JSON_VALUE(body, '$.http.status_code'), 'String')) NOT LIKE LOWER(?)", + expectedError: nil, + }, + { + name: "Between operator - string", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.status_code", + }, + operator: qbtypes.FilterOperatorBetween, + value: []any{"200", "300"}, + expectedSQL: "JSONExtract(JSON_VALUE(body, '$.http.status_code'), 'Int64') BETWEEN ? AND ?", + expectedError: nil, + }, + { + name: "Between operator - int64", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.status_code", + }, + operator: qbtypes.FilterOperatorBetween, + value: []any{400, 500}, + expectedSQL: "JSONExtract(JSON_VALUE(body, '$.http.status_code'), 'Int64') BETWEEN ? AND ?", + expectedError: nil, + }, + { + name: "In operator - string", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.status_code", + }, + operator: qbtypes.FilterOperatorIn, + value: []any{"200", "300"}, + expectedSQL: "JSONExtract(JSON_VALUE(body, '$.http.status_code'), 'Int64') IN (?, ?)", + expectedError: nil, + }, + { + name: "In operator - int64", + key: telemetrytypes.TelemetryFieldKey{ + Name: "body.http.status_code", + }, + operator: qbtypes.FilterOperatorIn, + value: []any{401, 404, 500}, + expectedSQL: "JSONExtract(JSON_VALUE(body, '$.http.status_code'), 'Int64') IN (?, ?, ?)", + expectedError: nil, + }, + } + + for _, tc := range testCases { + sb := sqlbuilder.NewSelectBuilder() + t.Run(tc.name, func(t *testing.T) { + cond, err := conditionBuilder.GetCondition(ctx, &tc.key, tc.operator, tc.value, sb) + sb.Where(cond) + + if tc.expectedError != nil { + assert.Equal(t, tc.expectedError, err) + } else { + require.NoError(t, err) + sql, _ := sb.BuildWithFlavor(sqlbuilder.ClickHouse) + assert.Contains(t, sql, tc.expectedSQL) + } + }) + } +} diff --git a/pkg/telemetrylogs/const.go b/pkg/telemetrylogs/const.go new file mode 100644 index 0000000000..1acc1fcff9 --- /dev/null +++ b/pkg/telemetrylogs/const.go @@ -0,0 +1,5 @@ +package telemetrylogs + +var ( + BodyJSONStringSearchPrefix = `body.` +) diff --git a/pkg/types/telemetrytypes/field.go b/pkg/types/telemetrytypes/field.go index 1fd7e3272f..26305c1ced 100644 --- a/pkg/types/telemetrytypes/field.go +++ b/pkg/types/telemetrytypes/field.go @@ -27,6 +27,18 @@ type TelemetryFieldKey struct { Materialized bool `json:"materialized,omitempty"` } +func (f TelemetryFieldKey) String() string { + var sb strings.Builder + sb.WriteString(fmt.Sprintf("name=%s", f.Name)) + if f.FieldContext != FieldContextUnspecified { + sb.WriteString(fmt.Sprintf(",context=%s", f.FieldContext.String)) + } + if f.FieldDataType != FieldDataTypeUnspecified { + sb.WriteString(fmt.Sprintf(",type=%s", f.FieldDataType.StringValue())) + } + return sb.String() +} + // GetFieldKeyFromKeyText returns a TelemetryFieldKey from a key text. // The key text is expected to be in the format of `fieldContext.fieldName:fieldDataType` in the search query. func GetFieldKeyFromKeyText(key string) TelemetryFieldKey { @@ -87,11 +99,11 @@ func GetFieldKeyFromKeyText(key string) TelemetryFieldKey { } func FieldKeyToMaterializedColumnName(key *TelemetryFieldKey) string { - return fmt.Sprintf("%s_%s_%s", key.FieldContext, key.FieldDataType.String, strings.ReplaceAll(key.Name, ".", "$$")) + return fmt.Sprintf("%s_%s_%s", key.FieldContext.String, fieldDataTypes[key.FieldDataType.StringValue()].StringValue(), strings.ReplaceAll(key.Name, ".", "$$")) } func FieldKeyToMaterializedColumnNameForExists(key *TelemetryFieldKey) string { - return fmt.Sprintf("%s_%s_%s_exists", key.FieldContext, key.FieldDataType.String, strings.ReplaceAll(key.Name, ".", "$$")) + return fmt.Sprintf("%s_%s_%s_exists", key.FieldContext.String, fieldDataTypes[key.FieldDataType.StringValue()].StringValue(), strings.ReplaceAll(key.Name, ".", "$$")) } type TelemetryFieldValues struct { diff --git a/pkg/types/telemetrytypes/field_datatype.go b/pkg/types/telemetrytypes/field_datatype.go index ec6ef62f72..07d91b9afb 100644 --- a/pkg/types/telemetrytypes/field_datatype.go +++ b/pkg/types/telemetrytypes/field_datatype.go @@ -23,6 +23,14 @@ var ( FieldDataTypeNumber = FieldDataType{valuer.NewString("number")} FieldDataTypeUnspecified = FieldDataType{valuer.NewString("")} + FieldDataTypeArrayString = FieldDataType{valuer.NewString("[]string")} + FieldDataTypeArrayFloat64 = FieldDataType{valuer.NewString("[]float64")} + FieldDataTypeArrayBool = FieldDataType{valuer.NewString("[]bool")} + + // int64 and number are synonyms for float64 + FieldDataTypeArrayInt64 = FieldDataType{valuer.NewString("[]int64")} + FieldDataTypeArrayNumber = FieldDataType{valuer.NewString("[]number")} + // Map string representations to FieldDataType values // We want to handle all the possible string representations of the data types. // Even if the user uses some non-standard representation, we want to be able to @@ -53,9 +61,43 @@ var ( "double": FieldDataTypeNumber, "decimal": FieldDataTypeNumber, "number": FieldDataTypeNumber, + + // Array types + "[]string": FieldDataTypeArrayString, + "[]int64": FieldDataTypeArrayInt64, + "[]float64": FieldDataTypeArrayFloat64, + "[]number": FieldDataTypeArrayNumber, + "[]bool": FieldDataTypeArrayBool, + + // c-style array types + "string[]": FieldDataTypeArrayString, + "int64[]": FieldDataTypeArrayInt64, + "float64[]": FieldDataTypeArrayFloat64, + "number[]": FieldDataTypeArrayNumber, + "bool[]": FieldDataTypeArrayBool, + } + + fieldDataTypeToCHDataType = map[FieldDataType]string{ + FieldDataTypeString: "String", + FieldDataTypeBool: "Bool", + FieldDataTypeNumber: "Float64", + FieldDataTypeInt64: "Int64", + FieldDataTypeFloat64: "Float64", + + FieldDataTypeArrayString: "Array(String)", + FieldDataTypeArrayInt64: "Array(Int64)", + FieldDataTypeArrayFloat64: "Array(Float64)", + FieldDataTypeArrayBool: "Array(Bool)", } ) +func (f FieldDataType) CHDataType() string { + if chDataType, ok := fieldDataTypeToCHDataType[f]; ok { + return chDataType + } + return "String" +} + // UnmarshalJSON implements the json.Unmarshaler interface func (f *FieldDataType) UnmarshalJSON(data []byte) error { var str string