exonware-xwnode 0.0.1.12__py3-none-any.whl
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.
- exonware/__init__.py +14 -0
- exonware/xwnode/__init__.py +127 -0
- exonware/xwnode/base.py +676 -0
- exonware/xwnode/config.py +178 -0
- exonware/xwnode/contracts.py +730 -0
- exonware/xwnode/errors.py +503 -0
- exonware/xwnode/facade.py +460 -0
- exonware/xwnode/strategies/__init__.py +158 -0
- exonware/xwnode/strategies/advisor.py +463 -0
- exonware/xwnode/strategies/edges/__init__.py +32 -0
- exonware/xwnode/strategies/edges/adj_list.py +227 -0
- exonware/xwnode/strategies/edges/adj_matrix.py +391 -0
- exonware/xwnode/strategies/edges/base.py +169 -0
- exonware/xwnode/strategies/flyweight.py +328 -0
- exonware/xwnode/strategies/impls/__init__.py +13 -0
- exonware/xwnode/strategies/impls/_base_edge.py +403 -0
- exonware/xwnode/strategies/impls/_base_node.py +307 -0
- exonware/xwnode/strategies/impls/edge_adj_list.py +353 -0
- exonware/xwnode/strategies/impls/edge_adj_matrix.py +445 -0
- exonware/xwnode/strategies/impls/edge_bidir_wrapper.py +455 -0
- exonware/xwnode/strategies/impls/edge_block_adj_matrix.py +539 -0
- exonware/xwnode/strategies/impls/edge_coo.py +533 -0
- exonware/xwnode/strategies/impls/edge_csc.py +447 -0
- exonware/xwnode/strategies/impls/edge_csr.py +492 -0
- exonware/xwnode/strategies/impls/edge_dynamic_adj_list.py +503 -0
- exonware/xwnode/strategies/impls/edge_flow_network.py +555 -0
- exonware/xwnode/strategies/impls/edge_hyperedge_set.py +516 -0
- exonware/xwnode/strategies/impls/edge_neural_graph.py +650 -0
- exonware/xwnode/strategies/impls/edge_octree.py +574 -0
- exonware/xwnode/strategies/impls/edge_property_store.py +655 -0
- exonware/xwnode/strategies/impls/edge_quadtree.py +519 -0
- exonware/xwnode/strategies/impls/edge_rtree.py +820 -0
- exonware/xwnode/strategies/impls/edge_temporal_edgeset.py +558 -0
- exonware/xwnode/strategies/impls/edge_tree_graph_basic.py +271 -0
- exonware/xwnode/strategies/impls/edge_weighted_graph.py +411 -0
- exonware/xwnode/strategies/manager.py +775 -0
- exonware/xwnode/strategies/metrics.py +538 -0
- exonware/xwnode/strategies/migration.py +432 -0
- exonware/xwnode/strategies/nodes/__init__.py +50 -0
- exonware/xwnode/strategies/nodes/_base_node.py +307 -0
- exonware/xwnode/strategies/nodes/adjacency_list.py +267 -0
- exonware/xwnode/strategies/nodes/aho_corasick.py +345 -0
- exonware/xwnode/strategies/nodes/array_list.py +209 -0
- exonware/xwnode/strategies/nodes/base.py +247 -0
- exonware/xwnode/strategies/nodes/deque.py +200 -0
- exonware/xwnode/strategies/nodes/hash_map.py +135 -0
- exonware/xwnode/strategies/nodes/heap.py +307 -0
- exonware/xwnode/strategies/nodes/linked_list.py +232 -0
- exonware/xwnode/strategies/nodes/node_aho_corasick.py +520 -0
- exonware/xwnode/strategies/nodes/node_array_list.py +175 -0
- exonware/xwnode/strategies/nodes/node_avl_tree.py +371 -0
- exonware/xwnode/strategies/nodes/node_b_plus_tree.py +542 -0
- exonware/xwnode/strategies/nodes/node_bitmap.py +420 -0
- exonware/xwnode/strategies/nodes/node_bitset_dynamic.py +513 -0
- exonware/xwnode/strategies/nodes/node_bloom_filter.py +347 -0
- exonware/xwnode/strategies/nodes/node_btree.py +357 -0
- exonware/xwnode/strategies/nodes/node_count_min_sketch.py +470 -0
- exonware/xwnode/strategies/nodes/node_cow_tree.py +473 -0
- exonware/xwnode/strategies/nodes/node_cuckoo_hash.py +392 -0
- exonware/xwnode/strategies/nodes/node_fenwick_tree.py +301 -0
- exonware/xwnode/strategies/nodes/node_hash_map.py +269 -0
- exonware/xwnode/strategies/nodes/node_heap.py +191 -0
- exonware/xwnode/strategies/nodes/node_hyperloglog.py +407 -0
- exonware/xwnode/strategies/nodes/node_linked_list.py +409 -0
- exonware/xwnode/strategies/nodes/node_lsm_tree.py +400 -0
- exonware/xwnode/strategies/nodes/node_ordered_map.py +390 -0
- exonware/xwnode/strategies/nodes/node_ordered_map_balanced.py +565 -0
- exonware/xwnode/strategies/nodes/node_patricia.py +512 -0
- exonware/xwnode/strategies/nodes/node_persistent_tree.py +378 -0
- exonware/xwnode/strategies/nodes/node_radix_trie.py +452 -0
- exonware/xwnode/strategies/nodes/node_red_black_tree.py +497 -0
- exonware/xwnode/strategies/nodes/node_roaring_bitmap.py +570 -0
- exonware/xwnode/strategies/nodes/node_segment_tree.py +289 -0
- exonware/xwnode/strategies/nodes/node_set_hash.py +354 -0
- exonware/xwnode/strategies/nodes/node_set_tree.py +480 -0
- exonware/xwnode/strategies/nodes/node_skip_list.py +316 -0
- exonware/xwnode/strategies/nodes/node_splay_tree.py +393 -0
- exonware/xwnode/strategies/nodes/node_suffix_array.py +487 -0
- exonware/xwnode/strategies/nodes/node_treap.py +387 -0
- exonware/xwnode/strategies/nodes/node_tree_graph_hybrid.py +1434 -0
- exonware/xwnode/strategies/nodes/node_trie.py +252 -0
- exonware/xwnode/strategies/nodes/node_union_find.py +187 -0
- exonware/xwnode/strategies/nodes/node_xdata_optimized.py +369 -0
- exonware/xwnode/strategies/nodes/priority_queue.py +209 -0
- exonware/xwnode/strategies/nodes/queue.py +161 -0
- exonware/xwnode/strategies/nodes/sparse_matrix.py +206 -0
- exonware/xwnode/strategies/nodes/stack.py +152 -0
- exonware/xwnode/strategies/nodes/trie.py +274 -0
- exonware/xwnode/strategies/nodes/union_find.py +283 -0
- exonware/xwnode/strategies/pattern_detector.py +603 -0
- exonware/xwnode/strategies/performance_monitor.py +487 -0
- exonware/xwnode/strategies/queries/__init__.py +24 -0
- exonware/xwnode/strategies/queries/base.py +236 -0
- exonware/xwnode/strategies/queries/cql.py +201 -0
- exonware/xwnode/strategies/queries/cypher.py +181 -0
- exonware/xwnode/strategies/queries/datalog.py +70 -0
- exonware/xwnode/strategies/queries/elastic_dsl.py +70 -0
- exonware/xwnode/strategies/queries/eql.py +70 -0
- exonware/xwnode/strategies/queries/flux.py +70 -0
- exonware/xwnode/strategies/queries/gql.py +70 -0
- exonware/xwnode/strategies/queries/graphql.py +240 -0
- exonware/xwnode/strategies/queries/gremlin.py +181 -0
- exonware/xwnode/strategies/queries/hiveql.py +214 -0
- exonware/xwnode/strategies/queries/hql.py +70 -0
- exonware/xwnode/strategies/queries/jmespath.py +219 -0
- exonware/xwnode/strategies/queries/jq.py +66 -0
- exonware/xwnode/strategies/queries/json_query.py +66 -0
- exonware/xwnode/strategies/queries/jsoniq.py +248 -0
- exonware/xwnode/strategies/queries/kql.py +70 -0
- exonware/xwnode/strategies/queries/linq.py +238 -0
- exonware/xwnode/strategies/queries/logql.py +70 -0
- exonware/xwnode/strategies/queries/mql.py +68 -0
- exonware/xwnode/strategies/queries/n1ql.py +210 -0
- exonware/xwnode/strategies/queries/partiql.py +70 -0
- exonware/xwnode/strategies/queries/pig.py +215 -0
- exonware/xwnode/strategies/queries/promql.py +70 -0
- exonware/xwnode/strategies/queries/sparql.py +220 -0
- exonware/xwnode/strategies/queries/sql.py +275 -0
- exonware/xwnode/strategies/queries/xml_query.py +66 -0
- exonware/xwnode/strategies/queries/xpath.py +223 -0
- exonware/xwnode/strategies/queries/xquery.py +258 -0
- exonware/xwnode/strategies/queries/xwnode_executor.py +332 -0
- exonware/xwnode/strategies/queries/xwquery_strategy.py +424 -0
- exonware/xwnode/strategies/registry.py +604 -0
- exonware/xwnode/strategies/simple.py +273 -0
- exonware/xwnode/strategies/utils.py +532 -0
- exonware/xwnode/types.py +912 -0
- exonware/xwnode/version.py +78 -0
- exonware_xwnode-0.0.1.12.dist-info/METADATA +169 -0
- exonware_xwnode-0.0.1.12.dist-info/RECORD +132 -0
- exonware_xwnode-0.0.1.12.dist-info/WHEEL +4 -0
- exonware_xwnode-0.0.1.12.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,223 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
XPath Query Strategy
|
4
|
+
|
5
|
+
This module implements the XPath query strategy for XML data queries.
|
6
|
+
|
7
|
+
Company: eXonware.com
|
8
|
+
Author: Eng. Muhammad AlShehri
|
9
|
+
Email: connect@exonware.com
|
10
|
+
Version: 0.0.1.12
|
11
|
+
Generation Date: January 2, 2025
|
12
|
+
"""
|
13
|
+
|
14
|
+
import re
|
15
|
+
from typing import Any, Dict, List, Optional, Union
|
16
|
+
from .base import ADocumentQueryStrategy
|
17
|
+
from ...errors import XWNodeTypeError, XWNodeValueError
|
18
|
+
from ...contracts import QueryMode, QueryTrait
|
19
|
+
|
20
|
+
|
21
|
+
class XPathStrategy(ADocumentQueryStrategy):
|
22
|
+
"""
|
23
|
+
XPath query strategy for XML data queries.
|
24
|
+
|
25
|
+
Supports:
|
26
|
+
- XPath 1.0 and 2.0 features
|
27
|
+
- Location paths and expressions
|
28
|
+
- Predicates and functions
|
29
|
+
- Axes and node tests
|
30
|
+
- Namespace support
|
31
|
+
"""
|
32
|
+
|
33
|
+
def __init__(self, **options):
|
34
|
+
super().__init__(**options)
|
35
|
+
self._mode = QueryMode.XPATH
|
36
|
+
self._traits = QueryTrait.DOCUMENT | QueryTrait.STRUCTURED | QueryTrait.ANALYTICAL
|
37
|
+
|
38
|
+
def execute(self, query: str, **kwargs) -> Any:
|
39
|
+
"""Execute XPath query."""
|
40
|
+
if not self.validate_query(query):
|
41
|
+
raise XWNodeValueError(f"Invalid XPath query: {query}")
|
42
|
+
|
43
|
+
query_type = self._get_query_type(query)
|
44
|
+
|
45
|
+
if query_type == "location_path":
|
46
|
+
return self._execute_location_path(query, **kwargs)
|
47
|
+
elif query_type == "expression":
|
48
|
+
return self._execute_expression(query, **kwargs)
|
49
|
+
elif query_type == "function":
|
50
|
+
return self._execute_function(query, **kwargs)
|
51
|
+
else:
|
52
|
+
raise XWNodeValueError(f"Unsupported query type: {query_type}")
|
53
|
+
|
54
|
+
def validate_query(self, query: str) -> bool:
|
55
|
+
"""Validate XPath query syntax."""
|
56
|
+
if not query or not isinstance(query, str):
|
57
|
+
return False
|
58
|
+
|
59
|
+
# Basic XPath validation
|
60
|
+
query = query.strip()
|
61
|
+
|
62
|
+
# Check for XPath syntax
|
63
|
+
if query.startswith("/") or query.startswith("//") or query.startswith("@") or query.startswith("."):
|
64
|
+
return True
|
65
|
+
|
66
|
+
# Check for XPath functions
|
67
|
+
xpath_functions = ["text", "name", "local-name", "namespace-uri", "count", "position", "last", "string", "number", "boolean", "not", "true", "false", "contains", "starts-with", "ends-with", "substring", "substring-before", "substring-after", "normalize-space", "translate", "concat", "string-length", "sum", "floor", "ceiling", "round", "id", "key", "document", "format-number", "unparsed-entity-uri", "unparsed-entity-public-id", "generate-id", "system-property", "element-available", "function-available", "current", "lang", "local-name", "namespace-uri", "name", "string", "number", "boolean", "not", "true", "false", "contains", "starts-with", "ends-with", "substring", "substring-before", "substring-after", "normalize-space", "translate", "concat", "string-length", "sum", "floor", "ceiling", "round", "id", "key", "document", "format-number", "unparsed-entity-uri", "unparsed-entity-public-id", "generate-id", "system-property", "element-available", "function-available", "current", "lang"]
|
68
|
+
|
69
|
+
for func in xpath_functions:
|
70
|
+
if func in query:
|
71
|
+
return True
|
72
|
+
|
73
|
+
# Check for axes
|
74
|
+
axes = ["ancestor", "ancestor-or-self", "attribute", "child", "descendant", "descendant-or-self", "following", "following-sibling", "namespace", "parent", "preceding", "preceding-sibling", "self"]
|
75
|
+
|
76
|
+
for axis in axes:
|
77
|
+
if f"{axis}::" in query:
|
78
|
+
return True
|
79
|
+
|
80
|
+
return False
|
81
|
+
|
82
|
+
def get_query_plan(self, query: str) -> Dict[str, Any]:
|
83
|
+
"""Get XPath query execution plan."""
|
84
|
+
query_type = self._get_query_type(query)
|
85
|
+
|
86
|
+
return {
|
87
|
+
"query_type": query_type,
|
88
|
+
"operation": query_type,
|
89
|
+
"complexity": self._estimate_complexity(query),
|
90
|
+
"estimated_cost": self._estimate_cost(query),
|
91
|
+
"expressions": self._extract_expressions(query),
|
92
|
+
"optimization_hints": self._get_optimization_hints(query)
|
93
|
+
}
|
94
|
+
|
95
|
+
def path_query(self, path: str) -> Any:
|
96
|
+
"""Execute path-based query."""
|
97
|
+
# XPath path queries
|
98
|
+
query = f"/{path}"
|
99
|
+
return self.execute(query)
|
100
|
+
|
101
|
+
def filter_query(self, filter_expression: str) -> Any:
|
102
|
+
"""Execute filter query."""
|
103
|
+
query = f"//*[{filter_expression}]"
|
104
|
+
return self.execute(query)
|
105
|
+
|
106
|
+
def projection_query(self, fields: List[str]) -> Any:
|
107
|
+
"""Execute projection query."""
|
108
|
+
if len(fields) == 1:
|
109
|
+
query = f"//{fields[0]}"
|
110
|
+
else:
|
111
|
+
field_list = " | ".join([f"//{field}" for field in fields])
|
112
|
+
query = f"({field_list})"
|
113
|
+
|
114
|
+
return self.execute(query)
|
115
|
+
|
116
|
+
def sort_query(self, sort_fields: List[str], order: str = "asc") -> Any:
|
117
|
+
"""Execute sort query."""
|
118
|
+
# XPath doesn't have built-in sorting, use position
|
119
|
+
if order.lower() == "desc":
|
120
|
+
query = f"//*[position() = last() - position() + 1]"
|
121
|
+
else:
|
122
|
+
query = f"//*[position()]"
|
123
|
+
|
124
|
+
return self.execute(query)
|
125
|
+
|
126
|
+
def limit_query(self, limit: int, offset: int = 0) -> Any:
|
127
|
+
"""Execute limit query."""
|
128
|
+
if offset > 0:
|
129
|
+
query = f"//*[position() > {offset} and position() <= {offset + limit}]"
|
130
|
+
else:
|
131
|
+
query = f"//*[position() <= {limit}]"
|
132
|
+
|
133
|
+
return self.execute(query)
|
134
|
+
|
135
|
+
def _get_query_type(self, query: str) -> str:
|
136
|
+
"""Extract query type from XPath query."""
|
137
|
+
query = query.strip()
|
138
|
+
|
139
|
+
if "/" in query or "//" in query:
|
140
|
+
return "location_path"
|
141
|
+
elif "(" in query and ")" in query:
|
142
|
+
return "function"
|
143
|
+
else:
|
144
|
+
return "expression"
|
145
|
+
|
146
|
+
def _execute_location_path(self, query: str, **kwargs) -> Any:
|
147
|
+
"""Execute location path."""
|
148
|
+
return {"result": "XPath location path executed", "query": query}
|
149
|
+
|
150
|
+
def _execute_expression(self, query: str, **kwargs) -> Any:
|
151
|
+
"""Execute expression."""
|
152
|
+
return {"result": "XPath expression executed", "query": query}
|
153
|
+
|
154
|
+
def _execute_function(self, query: str, **kwargs) -> Any:
|
155
|
+
"""Execute function call."""
|
156
|
+
return {"result": "XPath function executed", "query": query}
|
157
|
+
|
158
|
+
def _estimate_complexity(self, query: str) -> str:
|
159
|
+
"""Estimate query complexity."""
|
160
|
+
expressions = self._extract_expressions(query)
|
161
|
+
|
162
|
+
if len(expressions) > 5:
|
163
|
+
return "HIGH"
|
164
|
+
elif len(expressions) > 2:
|
165
|
+
return "MEDIUM"
|
166
|
+
else:
|
167
|
+
return "LOW"
|
168
|
+
|
169
|
+
def _estimate_cost(self, query: str) -> int:
|
170
|
+
"""Estimate query cost."""
|
171
|
+
complexity = self._estimate_complexity(query)
|
172
|
+
if complexity == "HIGH":
|
173
|
+
return 100
|
174
|
+
elif complexity == "MEDIUM":
|
175
|
+
return 50
|
176
|
+
else:
|
177
|
+
return 25
|
178
|
+
|
179
|
+
def _extract_expressions(self, query: str) -> List[str]:
|
180
|
+
"""Extract XPath expressions from query."""
|
181
|
+
expressions = []
|
182
|
+
|
183
|
+
# Location paths
|
184
|
+
if "/" in query:
|
185
|
+
expressions.append("path")
|
186
|
+
if "//" in query:
|
187
|
+
expressions.append("descendant")
|
188
|
+
if "@" in query:
|
189
|
+
expressions.append("attribute")
|
190
|
+
if "[" in query and "]" in query:
|
191
|
+
expressions.append("predicate")
|
192
|
+
|
193
|
+
# Axes
|
194
|
+
axes = ["ancestor", "ancestor-or-self", "attribute", "child", "descendant", "descendant-or-self", "following", "following-sibling", "namespace", "parent", "preceding", "preceding-sibling", "self"]
|
195
|
+
for axis in axes:
|
196
|
+
if f"{axis}::" in query:
|
197
|
+
expressions.append(axis)
|
198
|
+
|
199
|
+
# Functions
|
200
|
+
xpath_functions = ["text", "name", "local-name", "namespace-uri", "count", "position", "last", "string", "number", "boolean", "not", "true", "false", "contains", "starts-with", "ends-with", "substring", "substring-before", "substring-after", "normalize-space", "translate", "concat", "string-length", "sum", "floor", "ceiling", "round", "id", "key", "document", "format-number", "unparsed-entity-uri", "unparsed-entity-public-id", "generate-id", "system-property", "element-available", "function-available", "current", "lang"]
|
201
|
+
for func in xpath_functions:
|
202
|
+
if func in query:
|
203
|
+
expressions.append(func)
|
204
|
+
|
205
|
+
return expressions
|
206
|
+
|
207
|
+
def _get_optimization_hints(self, query: str) -> List[str]:
|
208
|
+
"""Get query optimization hints."""
|
209
|
+
hints = []
|
210
|
+
|
211
|
+
if "//" in query:
|
212
|
+
hints.append("Consider using specific paths instead of descendant navigation")
|
213
|
+
|
214
|
+
if "[" in query and "]" in query:
|
215
|
+
hints.append("Consider using indexes for predicate operations")
|
216
|
+
|
217
|
+
if "position()" in query:
|
218
|
+
hints.append("Consider using last() for better performance")
|
219
|
+
|
220
|
+
if "text()" in query:
|
221
|
+
hints.append("Consider using normalize-space() for text processing")
|
222
|
+
|
223
|
+
return hints
|
@@ -0,0 +1,258 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
XQuery Query Strategy
|
4
|
+
|
5
|
+
This module implements the XQuery query strategy for XML data queries.
|
6
|
+
|
7
|
+
Company: eXonware.com
|
8
|
+
Author: Eng. Muhammad AlShehri
|
9
|
+
Email: connect@exonware.com
|
10
|
+
Version: 0.0.1.12
|
11
|
+
Generation Date: January 2, 2025
|
12
|
+
"""
|
13
|
+
|
14
|
+
import re
|
15
|
+
from typing import Any, Dict, List, Optional, Union
|
16
|
+
from .base import ADocumentQueryStrategy
|
17
|
+
from ...errors import XWNodeTypeError, XWNodeValueError
|
18
|
+
from ...contracts import QueryMode, QueryTrait
|
19
|
+
|
20
|
+
|
21
|
+
class XQueryStrategy(ADocumentQueryStrategy):
|
22
|
+
"""
|
23
|
+
XQuery query strategy for XML data queries.
|
24
|
+
|
25
|
+
Supports:
|
26
|
+
- XQuery 1.0 and 3.0 features
|
27
|
+
- FLWOR expressions
|
28
|
+
- XPath expressions
|
29
|
+
- XML construction
|
30
|
+
- Functions and modules
|
31
|
+
"""
|
32
|
+
|
33
|
+
def __init__(self, **options):
|
34
|
+
super().__init__(**options)
|
35
|
+
self._mode = QueryMode.XQUERY
|
36
|
+
self._traits = QueryTrait.DOCUMENT | QueryTrait.STRUCTURED | QueryTrait.ANALYTICAL
|
37
|
+
|
38
|
+
def execute(self, query: str, **kwargs) -> Any:
|
39
|
+
"""Execute XQuery query."""
|
40
|
+
if not self.validate_query(query):
|
41
|
+
raise XWNodeValueError(f"Invalid XQuery query: {query}")
|
42
|
+
|
43
|
+
query_type = self._get_query_type(query)
|
44
|
+
|
45
|
+
if query_type == "flwor":
|
46
|
+
return self._execute_flwor(query, **kwargs)
|
47
|
+
elif query_type == "xpath":
|
48
|
+
return self._execute_xpath(query, **kwargs)
|
49
|
+
elif query_type == "construction":
|
50
|
+
return self._execute_construction(query, **kwargs)
|
51
|
+
else:
|
52
|
+
raise XWNodeValueError(f"Unsupported query type: {query_type}")
|
53
|
+
|
54
|
+
def validate_query(self, query: str) -> bool:
|
55
|
+
"""Validate XQuery query syntax."""
|
56
|
+
if not query or not isinstance(query, str):
|
57
|
+
return False
|
58
|
+
|
59
|
+
# Basic XQuery validation
|
60
|
+
query = query.strip()
|
61
|
+
|
62
|
+
# Check for XQuery keywords
|
63
|
+
xquery_keywords = ["for", "let", "where", "order by", "group by", "return", "declare", "namespace", "import", "module", "function", "variable", "element", "attribute", "text", "comment", "processing-instruction", "document", "collection"]
|
64
|
+
|
65
|
+
query_lower = query.lower()
|
66
|
+
for keyword in xquery_keywords:
|
67
|
+
if keyword in query_lower:
|
68
|
+
return True
|
69
|
+
|
70
|
+
# Check for XPath expressions
|
71
|
+
if "/" in query or "//" in query or "@" in query or "[" in query:
|
72
|
+
return True
|
73
|
+
|
74
|
+
return False
|
75
|
+
|
76
|
+
def get_query_plan(self, query: str) -> Dict[str, Any]:
|
77
|
+
"""Get XQuery query execution plan."""
|
78
|
+
query_type = self._get_query_type(query)
|
79
|
+
|
80
|
+
return {
|
81
|
+
"query_type": query_type,
|
82
|
+
"operation": query_type,
|
83
|
+
"complexity": self._estimate_complexity(query),
|
84
|
+
"estimated_cost": self._estimate_cost(query),
|
85
|
+
"expressions": self._extract_expressions(query),
|
86
|
+
"optimization_hints": self._get_optimization_hints(query)
|
87
|
+
}
|
88
|
+
|
89
|
+
def path_query(self, path: str) -> Any:
|
90
|
+
"""Execute path-based query."""
|
91
|
+
# XQuery path queries
|
92
|
+
query = f"doc()/{path}"
|
93
|
+
return self.execute(query)
|
94
|
+
|
95
|
+
def filter_query(self, filter_expression: str) -> Any:
|
96
|
+
"""Execute filter query."""
|
97
|
+
query = f"""
|
98
|
+
for $item in doc()//*
|
99
|
+
where {filter_expression}
|
100
|
+
return $item
|
101
|
+
"""
|
102
|
+
return self.execute(query)
|
103
|
+
|
104
|
+
def projection_query(self, fields: List[str]) -> Any:
|
105
|
+
"""Execute projection query."""
|
106
|
+
if len(fields) == 1:
|
107
|
+
query = f"""
|
108
|
+
for $item in doc()//*
|
109
|
+
return $item/{fields[0]}
|
110
|
+
"""
|
111
|
+
else:
|
112
|
+
field_list = ", ".join([f"$item/{field}" for field in fields])
|
113
|
+
query = f"""
|
114
|
+
for $item in doc()//*
|
115
|
+
return <result>{{ {field_list} }}</result>
|
116
|
+
"""
|
117
|
+
|
118
|
+
return self.execute(query)
|
119
|
+
|
120
|
+
def sort_query(self, sort_fields: List[str], order: str = "asc") -> Any:
|
121
|
+
"""Execute sort query."""
|
122
|
+
if order.lower() == "desc":
|
123
|
+
query = f"""
|
124
|
+
for $item in doc()//*
|
125
|
+
order by $item/{sort_fields[0]} descending
|
126
|
+
return $item
|
127
|
+
"""
|
128
|
+
else:
|
129
|
+
query = f"""
|
130
|
+
for $item in doc()//*
|
131
|
+
order by $item/{sort_fields[0]}
|
132
|
+
return $item
|
133
|
+
"""
|
134
|
+
|
135
|
+
return self.execute(query)
|
136
|
+
|
137
|
+
def limit_query(self, limit: int, offset: int = 0) -> Any:
|
138
|
+
"""Execute limit query."""
|
139
|
+
if offset > 0:
|
140
|
+
query = f"""
|
141
|
+
for $item at $pos in doc()//*
|
142
|
+
where $pos > {offset}
|
143
|
+
return $item
|
144
|
+
"""
|
145
|
+
# Use subsequence for limit
|
146
|
+
return self._execute_function(f"subsequence(doc()//*, {offset + 1}, {limit})")
|
147
|
+
else:
|
148
|
+
query = f"""
|
149
|
+
for $item in doc()//*
|
150
|
+
return $item
|
151
|
+
"""
|
152
|
+
return self._execute_function(f"subsequence(doc()//*, 1, {limit})")
|
153
|
+
|
154
|
+
def _get_query_type(self, query: str) -> str:
|
155
|
+
"""Extract query type from XQuery query."""
|
156
|
+
query = query.strip()
|
157
|
+
|
158
|
+
if "for" in query.lower() or "let" in query.lower():
|
159
|
+
return "flwor"
|
160
|
+
elif "<" in query and ">" in query:
|
161
|
+
return "construction"
|
162
|
+
elif "/" in query or "//" in query:
|
163
|
+
return "xpath"
|
164
|
+
else:
|
165
|
+
return "unknown"
|
166
|
+
|
167
|
+
def _execute_flwor(self, query: str, **kwargs) -> Any:
|
168
|
+
"""Execute FLWOR expression."""
|
169
|
+
return {"result": "XQuery FLWOR executed", "query": query}
|
170
|
+
|
171
|
+
def _execute_xpath(self, query: str, **kwargs) -> Any:
|
172
|
+
"""Execute XPath expression."""
|
173
|
+
return {"result": "XQuery XPath executed", "query": query}
|
174
|
+
|
175
|
+
def _execute_construction(self, query: str, **kwargs) -> Any:
|
176
|
+
"""Execute XML construction."""
|
177
|
+
return {"result": "XQuery construction executed", "query": query}
|
178
|
+
|
179
|
+
def _execute_function(self, query: str, **kwargs) -> Any:
|
180
|
+
"""Execute function call."""
|
181
|
+
return {"result": "XQuery function executed", "query": query}
|
182
|
+
|
183
|
+
def _estimate_complexity(self, query: str) -> str:
|
184
|
+
"""Estimate query complexity."""
|
185
|
+
expressions = self._extract_expressions(query)
|
186
|
+
|
187
|
+
if len(expressions) > 5:
|
188
|
+
return "HIGH"
|
189
|
+
elif len(expressions) > 2:
|
190
|
+
return "MEDIUM"
|
191
|
+
else:
|
192
|
+
return "LOW"
|
193
|
+
|
194
|
+
def _estimate_cost(self, query: str) -> int:
|
195
|
+
"""Estimate query cost."""
|
196
|
+
complexity = self._estimate_complexity(query)
|
197
|
+
if complexity == "HIGH":
|
198
|
+
return 150
|
199
|
+
elif complexity == "MEDIUM":
|
200
|
+
return 75
|
201
|
+
else:
|
202
|
+
return 35
|
203
|
+
|
204
|
+
def _extract_expressions(self, query: str) -> List[str]:
|
205
|
+
"""Extract XQuery expressions from query."""
|
206
|
+
expressions = []
|
207
|
+
|
208
|
+
# FLWOR expressions
|
209
|
+
if "for" in query.lower():
|
210
|
+
expressions.append("for")
|
211
|
+
if "let" in query.lower():
|
212
|
+
expressions.append("let")
|
213
|
+
if "where" in query.lower():
|
214
|
+
expressions.append("where")
|
215
|
+
if "order by" in query.lower():
|
216
|
+
expressions.append("order by")
|
217
|
+
if "group by" in query.lower():
|
218
|
+
expressions.append("group by")
|
219
|
+
if "return" in query.lower():
|
220
|
+
expressions.append("return")
|
221
|
+
|
222
|
+
# XPath expressions
|
223
|
+
if "/" in query:
|
224
|
+
expressions.append("path")
|
225
|
+
if "//" in query:
|
226
|
+
expressions.append("descendant")
|
227
|
+
if "@" in query:
|
228
|
+
expressions.append("attribute")
|
229
|
+
if "[" in query and "]" in query:
|
230
|
+
expressions.append("predicate")
|
231
|
+
|
232
|
+
# XML construction
|
233
|
+
if "<" in query and ">" in query:
|
234
|
+
expressions.append("construction")
|
235
|
+
|
236
|
+
# Functions
|
237
|
+
if "(" in query and ")" in query:
|
238
|
+
expressions.append("function")
|
239
|
+
|
240
|
+
return expressions
|
241
|
+
|
242
|
+
def _get_optimization_hints(self, query: str) -> List[str]:
|
243
|
+
"""Get query optimization hints."""
|
244
|
+
hints = []
|
245
|
+
|
246
|
+
if "//" in query:
|
247
|
+
hints.append("Consider using specific paths instead of descendant navigation")
|
248
|
+
|
249
|
+
if "for" in query.lower() and "let" in query.lower():
|
250
|
+
hints.append("Consider using let for computed values")
|
251
|
+
|
252
|
+
if "[" in query and "]" in query:
|
253
|
+
hints.append("Consider using indexes for predicate operations")
|
254
|
+
|
255
|
+
if "order by" in query.lower():
|
256
|
+
hints.append("Consider using indexes for ordered queries")
|
257
|
+
|
258
|
+
return hints
|