tellaro-query-language 0.1.2__tar.gz → 0.1.3__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.2 → tellaro_query_language-0.1.3}/PKG-INFO +1 -1
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/pyproject.toml +1 -1
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/core.py +93 -11
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/LICENSE +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/README.md +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/__init__.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/analyzer.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/cache/__init__.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/cache/base.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/cache/memory.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/cache/redis.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/core_components/README.md +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/core_components/__init__.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/core_components/file_operations.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/core_components/opensearch_operations.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/core_components/stats_operations.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/core_components/validation_operations.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/evaluator.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/evaluator_components/README.md +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/evaluator_components/__init__.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/evaluator_components/field_access.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/evaluator_components/special_expressions.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/evaluator_components/value_comparison.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/exceptions.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/geoip_normalizer.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/mutator_analyzer.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/mutators/__init__.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/mutators/base.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/mutators/dns.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/mutators/encoding.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/mutators/geo.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/mutators/list.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/mutators/network.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/mutators/security.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/mutators/string.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/opensearch.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/opensearch_components/README.md +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/opensearch_components/__init__.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/opensearch_components/field_mapping.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/opensearch_components/lucene_converter.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/opensearch_components/query_converter.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/opensearch_mappings.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/opensearch_stats.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/parser.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/parser_components/README.md +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/parser_components/__init__.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/parser_components/ast_builder.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/parser_components/error_analyzer.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/parser_components/field_extractor.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/parser_components/grammar.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/post_processor.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/scripts.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/stats_evaluator.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/stats_transformer.py +0 -0
- {tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/validators.py +0 -0
|
@@ -12,6 +12,7 @@ from .evaluator import TQLEvaluator
|
|
|
12
12
|
from .exceptions import TQLOperatorError, TQLParseError, TQLSyntaxError, TQLTypeError, TQLValidationError
|
|
13
13
|
from .mutator_analyzer import MutatorAnalysisResult
|
|
14
14
|
from .parser import TQLParser
|
|
15
|
+
from .stats_evaluator import TQLStatsEvaluator
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class TQL:
|
|
@@ -53,6 +54,7 @@ class TQL:
|
|
|
53
54
|
"""
|
|
54
55
|
self.parser = TQLParser()
|
|
55
56
|
self.evaluator = TQLEvaluator()
|
|
57
|
+
self.stats_evaluator = TQLStatsEvaluator()
|
|
56
58
|
self.field_mappings = field_mappings or {}
|
|
57
59
|
|
|
58
60
|
# Create enhanced field mappings for optimization
|
|
@@ -165,16 +167,25 @@ class TQL:
|
|
|
165
167
|
return f"NOT {operand}"
|
|
166
168
|
return str(ast)
|
|
167
169
|
|
|
168
|
-
def query(
|
|
169
|
-
|
|
170
|
+
def query(
|
|
171
|
+
self, data: Union[List[Dict], str], query: str, size: int = 10, save_enrichment: bool = False
|
|
172
|
+
) -> Dict[str, Any]: # noqa: C901
|
|
173
|
+
"""Execute a TQL query against data and return results in execute_opensearch format.
|
|
170
174
|
|
|
171
175
|
Args:
|
|
172
176
|
data: List of dictionaries or path to JSON/CSV file
|
|
173
|
-
query: TQL query string
|
|
177
|
+
query: TQL query string (can be filter query, stats query, or combined)
|
|
178
|
+
size: Number of documents to return (0 for stats-only queries)
|
|
174
179
|
save_enrichment: If True and mutators add enrichment fields, save back to source
|
|
175
180
|
|
|
176
181
|
Returns:
|
|
177
|
-
|
|
182
|
+
Dictionary containing:
|
|
183
|
+
- results: List of matching records (if size > 0 and no stats)
|
|
184
|
+
- stats: Stats results (if query contains stats)
|
|
185
|
+
- total: Total number of matching documents
|
|
186
|
+
- post_processing_applied: Whether post-processing was applied
|
|
187
|
+
- health_status: Query health status
|
|
188
|
+
- health_reasons: List of health issues
|
|
178
189
|
|
|
179
190
|
Raises:
|
|
180
191
|
TQLParseError: If query parsing fails
|
|
@@ -183,6 +194,9 @@ class TQL:
|
|
|
183
194
|
# Parse the query
|
|
184
195
|
ast = self.parse(query)
|
|
185
196
|
|
|
197
|
+
# Check query type
|
|
198
|
+
query_type = ast.get("type")
|
|
199
|
+
|
|
186
200
|
# Load data if it's a file path
|
|
187
201
|
if isinstance(data, str):
|
|
188
202
|
records = self.file_ops.load_file(data)
|
|
@@ -191,23 +205,64 @@ class TQL:
|
|
|
191
205
|
records = data
|
|
192
206
|
source_file = None
|
|
193
207
|
|
|
194
|
-
#
|
|
195
|
-
|
|
196
|
-
has_enrichments = False
|
|
208
|
+
# Initialize result structure
|
|
209
|
+
result = {"total": 0, "post_processing_applied": False, "health_status": "green", "health_reasons": []}
|
|
197
210
|
|
|
198
|
-
#
|
|
211
|
+
# Handle stats queries
|
|
212
|
+
if query_type == "stats_expr":
|
|
213
|
+
# This is a pure stats query like "| stats count()"
|
|
214
|
+
stats_result = self.stats(data, query)
|
|
215
|
+
# Convert to execute_opensearch format
|
|
216
|
+
result["stats"] = self._convert_stats_result(stats_result)
|
|
217
|
+
result["total"] = len(records)
|
|
218
|
+
return result
|
|
219
|
+
|
|
220
|
+
elif query_type == "query_with_stats":
|
|
221
|
+
# This is a combined query like "status = 'active' | stats count()"
|
|
222
|
+
# First filter the data
|
|
223
|
+
parsed = self.parse(query)
|
|
224
|
+
filter_ast = parsed["filter"]
|
|
225
|
+
stats_ast = parsed["stats"]
|
|
226
|
+
|
|
227
|
+
# Apply filter
|
|
228
|
+
filtered_records = []
|
|
229
|
+
for record in records:
|
|
230
|
+
if self.evaluator._evaluate_node(filter_ast, record, self._simple_mappings):
|
|
231
|
+
filtered_records.append(record)
|
|
232
|
+
|
|
233
|
+
# Apply stats to filtered data
|
|
234
|
+
stats_result = self.stats_evaluator.evaluate_stats(filtered_records, stats_ast)
|
|
235
|
+
result["stats"] = self._convert_stats_result(stats_result)
|
|
236
|
+
result["total"] = len(filtered_records)
|
|
237
|
+
|
|
238
|
+
# Include filtered documents if size > 0
|
|
239
|
+
if size > 0:
|
|
240
|
+
result["results"] = filtered_records[:size]
|
|
241
|
+
|
|
242
|
+
return result
|
|
243
|
+
|
|
244
|
+
# Handle regular filter queries
|
|
245
|
+
matched_records = []
|
|
246
|
+
has_enrichments = False
|
|
199
247
|
|
|
200
248
|
for record in records:
|
|
201
249
|
# Check if record matches
|
|
202
250
|
if self.evaluator._evaluate_node(ast, record, self._simple_mappings):
|
|
203
251
|
# Apply any mutators to enrich the record
|
|
204
252
|
enriched_record = self._apply_mutators_to_record(ast, record)
|
|
205
|
-
|
|
253
|
+
matched_records.append(enriched_record)
|
|
206
254
|
# Check if enrichments were added
|
|
207
255
|
if not has_enrichments and enriched_record is not record:
|
|
208
256
|
has_enrichments = True
|
|
209
257
|
|
|
210
|
-
#
|
|
258
|
+
# Set result data
|
|
259
|
+
result["total"] = len(matched_records)
|
|
260
|
+
if size > 0:
|
|
261
|
+
result["results"] = matched_records[:size]
|
|
262
|
+
|
|
263
|
+
# Check if post-processing (mutators) were applied
|
|
264
|
+
if has_enrichments:
|
|
265
|
+
result["post_processing_applied"] = True
|
|
211
266
|
|
|
212
267
|
# Save enrichments if requested
|
|
213
268
|
if save_enrichment and has_enrichments and source_file:
|
|
@@ -221,7 +276,7 @@ class TQL:
|
|
|
221
276
|
if source_file.lower().endswith(".json"):
|
|
222
277
|
self.file_ops.save_enrichments_to_json(source_file, all_enriched)
|
|
223
278
|
|
|
224
|
-
return
|
|
279
|
+
return result
|
|
225
280
|
|
|
226
281
|
def query_single(self, record: Dict[str, Any], query: str) -> bool:
|
|
227
282
|
"""Check if a single record matches a TQL query.
|
|
@@ -927,3 +982,30 @@ class TQL:
|
|
|
927
982
|
# For now, return the original record
|
|
928
983
|
# TODO: Implement mutator application for enrichment # noqa: W0511
|
|
929
984
|
return record
|
|
985
|
+
|
|
986
|
+
def _convert_stats_result(self, stats_result: Dict[str, Any]) -> Dict[str, Any]:
|
|
987
|
+
"""Convert stats result from query() format to execute_opensearch format.
|
|
988
|
+
|
|
989
|
+
Args:
|
|
990
|
+
stats_result: Result from stats() or query_stats() method
|
|
991
|
+
|
|
992
|
+
Returns:
|
|
993
|
+
Stats result in execute_opensearch format
|
|
994
|
+
"""
|
|
995
|
+
# Map the stats evaluator format to execute_opensearch format
|
|
996
|
+
if stats_result.get("type") == "simple_aggregation":
|
|
997
|
+
return {
|
|
998
|
+
"type": "stats",
|
|
999
|
+
"operation": stats_result["function"],
|
|
1000
|
+
"field": stats_result["field"],
|
|
1001
|
+
"values": stats_result["value"],
|
|
1002
|
+
}
|
|
1003
|
+
elif stats_result.get("type") == "multiple_aggregations":
|
|
1004
|
+
# For multiple aggregations, return the results dict
|
|
1005
|
+
return {"type": "stats_multiple", "results": stats_result["results"]}
|
|
1006
|
+
elif stats_result.get("type") == "grouped_aggregation":
|
|
1007
|
+
# For grouped aggregations
|
|
1008
|
+
return {"type": "stats_grouped", "group_by": stats_result["group_by"], "results": stats_result["results"]}
|
|
1009
|
+
else:
|
|
1010
|
+
# Return as-is if format is unknown
|
|
1011
|
+
return stats_result
|
|
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.2 → tellaro_query_language-0.1.3}/src/tql/core_components/README.md
RENAMED
|
File without changes
|
{tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/core_components/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/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.2 → tellaro_query_language-0.1.3}/src/tql/opensearch_mappings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/parser_components/README.md
RENAMED
|
File without changes
|
{tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/src/tql/parser_components/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tellaro_query_language-0.1.2 → tellaro_query_language-0.1.3}/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
|