tellaro-query-language 0.1.8__tar.gz → 0.2.0__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.8 → tellaro_query_language-0.2.0}/PKG-INFO +1 -1
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/pyproject.toml +1 -1
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/core.py +26 -3
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/core_components/opensearch_operations.py +13 -6
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/evaluator.py +4 -1
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/opensearch_components/lucene_converter.py +4 -1
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/opensearch_components/query_converter.py +4 -1
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/parser.py +5 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/LICENSE +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/README.md +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/__init__.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/analyzer.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/cache/__init__.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/cache/base.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/cache/memory.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/cache/redis.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/core_components/README.md +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/core_components/__init__.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/core_components/file_operations.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/core_components/stats_operations.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/core_components/validation_operations.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/evaluator_components/README.md +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/evaluator_components/__init__.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/evaluator_components/field_access.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/evaluator_components/special_expressions.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/evaluator_components/value_comparison.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/exceptions.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/geoip_normalizer.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/mutator_analyzer.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/mutators/__init__.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/mutators/base.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/mutators/dns.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/mutators/encoding.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/mutators/geo.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/mutators/list.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/mutators/network.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/mutators/security.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/mutators/string.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/opensearch.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/opensearch_components/README.md +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/opensearch_components/__init__.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/opensearch_components/field_mapping.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/opensearch_mappings.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/opensearch_stats.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/parser_components/README.md +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/parser_components/__init__.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/parser_components/ast_builder.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/parser_components/error_analyzer.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/parser_components/field_extractor.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/parser_components/grammar.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/post_processor.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/scripts.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/stats_evaluator.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/stats_transformer.py +0 -0
- {tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/validators.py +0 -0
|
@@ -450,7 +450,8 @@ class TQL:
|
|
|
450
450
|
index: Optional[str] = None,
|
|
451
451
|
query: Optional[str] = None,
|
|
452
452
|
size: int = 500,
|
|
453
|
-
|
|
453
|
+
search_after: Optional[List[Any]] = None,
|
|
454
|
+
sort: Optional[List[Dict[str, Any]]] = None,
|
|
454
455
|
timestamp_field: str = "@timestamp",
|
|
455
456
|
time_range: Optional[Dict[str, str]] = None,
|
|
456
457
|
scan_all: bool = False,
|
|
@@ -468,7 +469,8 @@ class TQL:
|
|
|
468
469
|
index: Index name to search
|
|
469
470
|
query: The TQL query string
|
|
470
471
|
size: Number of results to return (default: 500)
|
|
471
|
-
|
|
472
|
+
search_after: Values from previous result's sort field for pagination
|
|
473
|
+
sort: Sort order specification (e.g., [{"@timestamp": "desc"}, {"_id": "asc"}])
|
|
472
474
|
timestamp_field: Field name for timestamp filtering (default: "@timestamp")
|
|
473
475
|
time_range: Optional time range dict with 'gte' and/or 'lte' keys
|
|
474
476
|
scan_all: If True, use scroll API to retrieve all matching documents
|
|
@@ -480,6 +482,7 @@ class TQL:
|
|
|
480
482
|
Dictionary containing:
|
|
481
483
|
- results: List of processed results
|
|
482
484
|
- total: Total number of matching documents
|
|
485
|
+
- sort_values: Sort values of the last document (for search_after pagination)
|
|
483
486
|
- post_processing_applied: Whether post-processing was applied
|
|
484
487
|
- health_status: Query health status
|
|
485
488
|
- health_reasons: List of health issues
|
|
@@ -503,6 +506,24 @@ class TQL:
|
|
|
503
506
|
# Remove parameters that the new implementation doesn't understand
|
|
504
507
|
filtered_kwargs = {k: v for k, v in kwargs.items() if k not in ["save_enrichment", "opensearch_client"]}
|
|
505
508
|
|
|
509
|
+
# Check for backward compatibility - if from_ is in kwargs, it's old usage
|
|
510
|
+
if "from_" in kwargs:
|
|
511
|
+
# Old style pagination - convert to search_after with default sort
|
|
512
|
+
from_ = kwargs.pop("from_")
|
|
513
|
+
if from_ > 0 and not sort:
|
|
514
|
+
# Need a sort for proper pagination
|
|
515
|
+
sort = [{"_id": "asc"}]
|
|
516
|
+
# Note: We can't directly convert from_ to search_after without previous results
|
|
517
|
+
# This is a limitation of moving to search_after
|
|
518
|
+
if from_ > 0:
|
|
519
|
+
import warnings
|
|
520
|
+
|
|
521
|
+
warnings.warn(
|
|
522
|
+
"from_ parameter is deprecated. Use search_after with sort for efficient pagination.",
|
|
523
|
+
DeprecationWarning,
|
|
524
|
+
stacklevel=2,
|
|
525
|
+
)
|
|
526
|
+
|
|
506
527
|
# Add the supported parameters
|
|
507
528
|
filtered_kwargs.update(
|
|
508
529
|
{
|
|
@@ -511,6 +532,8 @@ class TQL:
|
|
|
511
532
|
"scan_all": scan_all,
|
|
512
533
|
"scroll_size": scroll_size,
|
|
513
534
|
"scroll_timeout": scroll_timeout,
|
|
535
|
+
"search_after": search_after,
|
|
536
|
+
"sort": sort,
|
|
514
537
|
}
|
|
515
538
|
)
|
|
516
539
|
|
|
@@ -519,7 +542,7 @@ class TQL:
|
|
|
519
542
|
filtered_kwargs["client"] = opensearch_client
|
|
520
543
|
|
|
521
544
|
# Execute using new implementation
|
|
522
|
-
results = self.opensearch_ops.execute_opensearch(query, index=index, size=size,
|
|
545
|
+
results = self.opensearch_ops.execute_opensearch(query, index=index, size=size, **filtered_kwargs)
|
|
523
546
|
|
|
524
547
|
# Convert to old format if needed
|
|
525
548
|
if isinstance(results, list):
|
|
@@ -141,7 +141,7 @@ class OpenSearchOperations:
|
|
|
141
141
|
query: str,
|
|
142
142
|
index: Optional[str] = None,
|
|
143
143
|
size: int = 10000,
|
|
144
|
-
|
|
144
|
+
search_after: Optional[List[Any]] = None,
|
|
145
145
|
sort: Optional[List[Dict[str, Any]]] = None,
|
|
146
146
|
source_includes: Optional[List[str]] = None,
|
|
147
147
|
source_excludes: Optional[List[str]] = None,
|
|
@@ -175,8 +175,8 @@ class OpenSearchOperations:
|
|
|
175
175
|
query: TQL query string
|
|
176
176
|
index: OpenSearch index name (uses environment variable if not provided)
|
|
177
177
|
size: Maximum number of results to return (default: 10000)
|
|
178
|
-
|
|
179
|
-
sort: List of sort specifications
|
|
178
|
+
search_after: Values from previous result for pagination
|
|
179
|
+
sort: List of sort specifications (required for search_after)
|
|
180
180
|
source_includes: Fields to include in response
|
|
181
181
|
source_excludes: Fields to exclude from response
|
|
182
182
|
track_total_hits: Whether to track total hit count
|
|
@@ -322,11 +322,13 @@ class OpenSearchOperations:
|
|
|
322
322
|
else:
|
|
323
323
|
search_body["query"] = time_filter
|
|
324
324
|
|
|
325
|
-
search_body.update({"size": size, "
|
|
325
|
+
search_body.update({"size": size, "track_total_hits": track_total_hits})
|
|
326
326
|
|
|
327
327
|
# Add optional parameters
|
|
328
328
|
if sort:
|
|
329
329
|
search_body["sort"] = sort
|
|
330
|
+
if search_after:
|
|
331
|
+
search_body["search_after"] = search_after
|
|
330
332
|
if source_includes or source_excludes:
|
|
331
333
|
search_body["_source"] = {}
|
|
332
334
|
if source_includes:
|
|
@@ -705,11 +707,16 @@ class OpenSearchOperations:
|
|
|
705
707
|
if not scan_all:
|
|
706
708
|
result["pagination"] = {
|
|
707
709
|
"size": size,
|
|
708
|
-
"from": from_,
|
|
709
710
|
"total": opensearch_total,
|
|
710
|
-
"has_more":
|
|
711
|
+
"has_more": len(hits) == size, # If we got a full page, there might be more
|
|
711
712
|
}
|
|
712
713
|
|
|
714
|
+
# Add sort values from the last hit for search_after pagination
|
|
715
|
+
if hits and sort:
|
|
716
|
+
last_hit = hits[-1]
|
|
717
|
+
if "sort" in last_hit:
|
|
718
|
+
result["sort_values"] = last_hit["sort"]
|
|
719
|
+
|
|
713
720
|
return result
|
|
714
721
|
|
|
715
722
|
def _docs_match(self, doc1: Dict[str, Any], doc2: Dict[str, Any]) -> bool:
|
|
@@ -81,7 +81,10 @@ class TQLEvaluator:
|
|
|
81
81
|
if isinstance(node, dict):
|
|
82
82
|
node_type = node.get("type")
|
|
83
83
|
|
|
84
|
-
if node_type == "
|
|
84
|
+
if node_type == "match_all":
|
|
85
|
+
# Empty query matches all records
|
|
86
|
+
return True
|
|
87
|
+
elif node_type == "comparison":
|
|
85
88
|
return self._evaluate_comparison(node, record, field_mappings)
|
|
86
89
|
elif node_type == "logical_op":
|
|
87
90
|
return self._evaluate_logical_op(node, record, field_mappings)
|
|
@@ -31,7 +31,10 @@ class LuceneConverter:
|
|
|
31
31
|
if isinstance(node, dict):
|
|
32
32
|
node_type = node.get("type")
|
|
33
33
|
|
|
34
|
-
if node_type == "
|
|
34
|
+
if node_type == "match_all":
|
|
35
|
+
# Empty query matches all documents in Lucene
|
|
36
|
+
return "*:*"
|
|
37
|
+
elif node_type == "comparison":
|
|
35
38
|
return self._convert_comparison_to_lucene(node)
|
|
36
39
|
elif node_type == "logical_op":
|
|
37
40
|
return self._convert_logical_op_to_lucene(node)
|
|
@@ -27,7 +27,10 @@ class QueryConverter:
|
|
|
27
27
|
if isinstance(node, dict):
|
|
28
28
|
node_type = node.get("type")
|
|
29
29
|
|
|
30
|
-
if node_type == "
|
|
30
|
+
if node_type == "match_all":
|
|
31
|
+
# Empty query matches all documents
|
|
32
|
+
return {"match_all": {}}
|
|
33
|
+
elif node_type == "comparison":
|
|
31
34
|
return self._convert_comparison(node)
|
|
32
35
|
elif node_type == "logical_op":
|
|
33
36
|
return self._convert_logical_op(node)
|
|
@@ -43,6 +43,11 @@ class TQLParser:
|
|
|
43
43
|
Raises:
|
|
44
44
|
TQLParseError: If the query has invalid syntax
|
|
45
45
|
"""
|
|
46
|
+
# Handle empty or whitespace-only queries
|
|
47
|
+
if not query or not query.strip():
|
|
48
|
+
# Return a special AST that matches all records
|
|
49
|
+
return {"type": "match_all"}
|
|
50
|
+
|
|
46
51
|
try:
|
|
47
52
|
# Parse the query
|
|
48
53
|
parsed_result = self.grammar.tql_expr.parseString(query, parseAll=True)
|
|
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.8 → tellaro_query_language-0.2.0}/src/tql/core_components/README.md
RENAMED
|
File without changes
|
{tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/core_components/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/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
|
{tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/opensearch_mappings.py
RENAMED
|
File without changes
|
|
File without changes
|
{tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/parser_components/README.md
RENAMED
|
File without changes
|
{tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/parser_components/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tellaro_query_language-0.1.8 → tellaro_query_language-0.2.0}/src/tql/parser_components/grammar.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|