tellaro-query-language 0.1.4__tar.gz → 0.1.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/PKG-INFO +1 -1
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/pyproject.toml +1 -1
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/core_components/stats_operations.py +19 -7
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/parser.py +32 -2
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/parser_components/grammar.py +14 -4
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/stats_evaluator.py +12 -1
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/LICENSE +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/README.md +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/__init__.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/analyzer.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/cache/__init__.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/cache/base.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/cache/memory.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/cache/redis.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/core.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/core_components/README.md +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/core_components/__init__.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/core_components/file_operations.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/core_components/opensearch_operations.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/core_components/validation_operations.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/evaluator.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/evaluator_components/README.md +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/evaluator_components/__init__.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/evaluator_components/field_access.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/evaluator_components/special_expressions.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/evaluator_components/value_comparison.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/exceptions.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/geoip_normalizer.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/mutator_analyzer.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/mutators/__init__.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/mutators/base.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/mutators/dns.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/mutators/encoding.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/mutators/geo.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/mutators/list.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/mutators/network.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/mutators/security.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/mutators/string.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/opensearch.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/opensearch_components/README.md +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/opensearch_components/__init__.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/opensearch_components/field_mapping.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/opensearch_components/lucene_converter.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/opensearch_components/query_converter.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/opensearch_mappings.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/opensearch_stats.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/parser_components/README.md +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/parser_components/__init__.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/parser_components/ast_builder.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/parser_components/error_analyzer.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/parser_components/field_extractor.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/post_processor.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/scripts.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/stats_transformer.py +0 -0
- {tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/validators.py +0 -0
|
@@ -38,15 +38,27 @@ class StatsOperations:
|
|
|
38
38
|
TQLParseError: If query parsing fails
|
|
39
39
|
TQLValueError: If query is invalid
|
|
40
40
|
"""
|
|
41
|
-
#
|
|
42
|
-
if not stats_query.strip().startswith("| stats"):
|
|
43
|
-
stats_query = "| stats " + stats_query.strip()
|
|
44
|
-
|
|
45
|
-
# Parse the stats expression
|
|
41
|
+
# First try to parse as-is
|
|
46
42
|
try:
|
|
47
43
|
parsed = self.parser.parse(stats_query)
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
# If it's already a stats expression, use it
|
|
45
|
+
if parsed.get("type") == "stats_expr":
|
|
46
|
+
# Already a valid stats expression, proceed
|
|
47
|
+
pass
|
|
48
|
+
else:
|
|
49
|
+
# Not a stats expression, try adding | stats prefix
|
|
50
|
+
stats_query_with_pipe = "| stats " + stats_query.strip()
|
|
51
|
+
parsed = self.parser.parse(stats_query_with_pipe)
|
|
52
|
+
except TQLParseError:
|
|
53
|
+
# If parsing failed, try with | stats prefix
|
|
54
|
+
if not stats_query.strip().startswith("| stats"):
|
|
55
|
+
stats_query_with_pipe = "| stats " + stats_query.strip()
|
|
56
|
+
try:
|
|
57
|
+
parsed = self.parser.parse(stats_query_with_pipe)
|
|
58
|
+
except TQLParseError as e:
|
|
59
|
+
raise TQLParseError(f"Invalid stats query: {str(e)}")
|
|
60
|
+
else:
|
|
61
|
+
raise
|
|
50
62
|
|
|
51
63
|
# Verify it's a stats expression
|
|
52
64
|
if parsed.get("type") != "stats_expr":
|
|
@@ -123,6 +123,10 @@ class TQLParser:
|
|
|
123
123
|
# Single item, check if it's a field with is_private/is_global mutator
|
|
124
124
|
item = parsed[0]
|
|
125
125
|
if isinstance(item, list):
|
|
126
|
+
# Check if this is a stats expression (starts with 'stats')
|
|
127
|
+
if len(item) >= 2 and isinstance(item[0], str) and item[0].lower() == "stats":
|
|
128
|
+
# This is a stats expression without filter
|
|
129
|
+
return self._build_stats_ast(item)
|
|
126
130
|
# Could be a typed_field
|
|
127
131
|
field_name, type_hint, field_mutators = self.ast_builder.extract_field_info(item)
|
|
128
132
|
if field_mutators:
|
|
@@ -1219,8 +1223,23 @@ class TQLParser:
|
|
|
1219
1223
|
result["aggregations"].append({"function": "count", "field": "*", "alias": None})
|
|
1220
1224
|
i += 1
|
|
1221
1225
|
elif isinstance(parsed[i], list):
|
|
1222
|
-
#
|
|
1223
|
-
|
|
1226
|
+
# Check if this is a single aggregation with alias pattern
|
|
1227
|
+
# Pattern: [['func', 'field'], 'as', 'alias'] or ['count', 'as', 'alias']
|
|
1228
|
+
if (
|
|
1229
|
+
len(parsed[i]) >= 3
|
|
1230
|
+
and isinstance(parsed[i][1], str)
|
|
1231
|
+
and parsed[i][1].lower() == "as"
|
|
1232
|
+
and (
|
|
1233
|
+
isinstance(parsed[i][0], list)
|
|
1234
|
+
or (isinstance(parsed[i][0], str) and parsed[i][0].lower() == "count")
|
|
1235
|
+
)
|
|
1236
|
+
):
|
|
1237
|
+
# This is a single aggregation with alias
|
|
1238
|
+
items_to_process = [parsed[i]]
|
|
1239
|
+
else:
|
|
1240
|
+
# This is a list of aggregations
|
|
1241
|
+
items_to_process = parsed[i]
|
|
1242
|
+
for item in items_to_process:
|
|
1224
1243
|
agg_dict: Dict[str, Any] = {}
|
|
1225
1244
|
|
|
1226
1245
|
if isinstance(item, str) and item.lower() == "count":
|
|
@@ -1228,6 +1247,17 @@ class TQLParser:
|
|
|
1228
1247
|
agg_dict["function"] = "count"
|
|
1229
1248
|
agg_dict["field"] = "*"
|
|
1230
1249
|
agg_dict["alias"] = None
|
|
1250
|
+
elif (
|
|
1251
|
+
isinstance(item, list)
|
|
1252
|
+
and len(item) >= 3
|
|
1253
|
+
and isinstance(item[0], str)
|
|
1254
|
+
and item[0].lower() == "count"
|
|
1255
|
+
and item[1].lower() == "as"
|
|
1256
|
+
):
|
|
1257
|
+
# count(*) with alias: ['count', 'as', 'alias']
|
|
1258
|
+
agg_dict["function"] = "count"
|
|
1259
|
+
agg_dict["field"] = "*"
|
|
1260
|
+
agg_dict["alias"] = item[2]
|
|
1231
1261
|
elif isinstance(item, list):
|
|
1232
1262
|
# Regular aggregation: [func, field, ...] or [[func, field], 'as', 'alias']
|
|
1233
1263
|
if len(item) >= 2 and isinstance(item[0], list):
|
{tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/parser_components/grammar.py
RENAMED
|
@@ -375,7 +375,8 @@ class TQLGrammar:
|
|
|
375
375
|
# Aggregation function names - including aliases
|
|
376
376
|
self.agg_function_name = oneOf(
|
|
377
377
|
"count unique_count sum min max average avg median med std standard_deviation "
|
|
378
|
-
"percentile percentiles p pct percentile_rank percentile_ranks pct_rank pct_ranks"
|
|
378
|
+
"percentile percentiles p pct percentile_rank percentile_ranks pct_rank pct_ranks "
|
|
379
|
+
"values unique cardinality",
|
|
379
380
|
caseless=True,
|
|
380
381
|
)
|
|
381
382
|
|
|
@@ -407,10 +408,18 @@ class TQLGrammar:
|
|
|
407
408
|
self.group_by_fields = delimitedList(self.field_name)
|
|
408
409
|
|
|
409
410
|
# Complete stats expression: | stats agg_functions [by group_fields]
|
|
410
|
-
self.
|
|
411
|
+
self.stats_expr_with_pipe = Group(
|
|
411
412
|
Suppress("|") + self.stats_kw + self.agg_list + PyparsingOptional(self.by_kw + self.group_by_fields)
|
|
412
413
|
)
|
|
413
414
|
|
|
415
|
+
# Stats expression without pipe (for standalone use)
|
|
416
|
+
self.stats_expr_no_pipe = Group(
|
|
417
|
+
self.stats_kw + self.agg_list + PyparsingOptional(self.by_kw + self.group_by_fields)
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
# Combined stats expression (with or without pipe)
|
|
421
|
+
self.stats_expr = self.stats_expr_with_pipe | self.stats_expr_no_pipe
|
|
422
|
+
|
|
414
423
|
def _setup_final_expressions(self):
|
|
415
424
|
"""Set up final expression definitions."""
|
|
416
425
|
# Define all forms of comparison
|
|
@@ -447,8 +456,9 @@ class TQLGrammar:
|
|
|
447
456
|
self.tql_expr << (
|
|
448
457
|
# filter | stats
|
|
449
458
|
(
|
|
450
|
-
|
|
451
|
-
| self.
|
|
459
|
+
self.stats_expr_no_pipe # just stats without pipe (applies to all records)
|
|
460
|
+
| Group(self.filter_expr + self.stats_expr_with_pipe) # filter | stats
|
|
461
|
+
| self.stats_expr # just stats with pipe (applies to all records)
|
|
452
462
|
| self.filter_expr
|
|
453
463
|
) # just filter (no stats)
|
|
454
464
|
)
|
|
@@ -40,7 +40,7 @@ class TQLStatsEvaluator:
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
# Aggregation functions that work with any field type
|
|
43
|
-
ANY_TYPE_AGGREGATIONS = {"count", "unique_count"}
|
|
43
|
+
ANY_TYPE_AGGREGATIONS = {"count", "unique_count", "values", "unique", "cardinality"}
|
|
44
44
|
|
|
45
45
|
# Numeric types supported by OpenSearch
|
|
46
46
|
NUMERIC_TYPES = {
|
|
@@ -281,6 +281,17 @@ class TQLStatsEvaluator:
|
|
|
281
281
|
for v in rank_values:
|
|
282
282
|
result[f"rank_{v}"] = self._calculate_percentile_rank(numeric_values, v)
|
|
283
283
|
return result
|
|
284
|
+
elif func in ["values", "unique", "cardinality"]:
|
|
285
|
+
# Return unique values from the field
|
|
286
|
+
unique_values = list(set(values)) if values else []
|
|
287
|
+
# Sort the values for consistent output
|
|
288
|
+
try:
|
|
289
|
+
# Try to sort if values are comparable
|
|
290
|
+
unique_values.sort()
|
|
291
|
+
except TypeError:
|
|
292
|
+
# If values aren't comparable (mixed types), just return unsorted
|
|
293
|
+
pass
|
|
294
|
+
return unique_values
|
|
284
295
|
else:
|
|
285
296
|
raise TQLError(f"Unsupported aggregation function: {func}")
|
|
286
297
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/core_components/README.md
RENAMED
|
File without changes
|
{tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/core_components/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/evaluator_components/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/opensearch_mappings.py
RENAMED
|
File without changes
|
|
File without changes
|
{tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/parser_components/README.md
RENAMED
|
File without changes
|
{tellaro_query_language-0.1.4 → tellaro_query_language-0.1.6}/src/tql/parser_components/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|