exonware-xwnode 0.0.1.22__py3-none-any.whl → 0.0.1.23__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.
Files changed (248) hide show
  1. exonware/__init__.py +1 -1
  2. exonware/xwnode/__init__.py +18 -5
  3. exonware/xwnode/add_strategy_types.py +165 -0
  4. exonware/xwnode/common/__init__.py +1 -1
  5. exonware/xwnode/common/graph/__init__.py +30 -0
  6. exonware/xwnode/common/graph/caching.py +131 -0
  7. exonware/xwnode/common/graph/contracts.py +100 -0
  8. exonware/xwnode/common/graph/errors.py +44 -0
  9. exonware/xwnode/common/graph/indexing.py +260 -0
  10. exonware/xwnode/common/graph/manager.py +568 -0
  11. exonware/xwnode/common/management/__init__.py +3 -5
  12. exonware/xwnode/common/management/manager.py +2 -2
  13. exonware/xwnode/common/management/migration.py +3 -3
  14. exonware/xwnode/common/monitoring/__init__.py +3 -5
  15. exonware/xwnode/common/monitoring/metrics.py +6 -2
  16. exonware/xwnode/common/monitoring/pattern_detector.py +1 -1
  17. exonware/xwnode/common/monitoring/performance_monitor.py +5 -1
  18. exonware/xwnode/common/patterns/__init__.py +3 -5
  19. exonware/xwnode/common/patterns/flyweight.py +5 -1
  20. exonware/xwnode/common/patterns/registry.py +202 -183
  21. exonware/xwnode/common/utils/__init__.py +25 -11
  22. exonware/xwnode/common/utils/simple.py +1 -1
  23. exonware/xwnode/config.py +3 -8
  24. exonware/xwnode/contracts.py +4 -105
  25. exonware/xwnode/defs.py +413 -159
  26. exonware/xwnode/edges/strategies/__init__.py +86 -4
  27. exonware/xwnode/edges/strategies/_base_edge.py +2 -2
  28. exonware/xwnode/edges/strategies/adj_list.py +287 -121
  29. exonware/xwnode/edges/strategies/adj_matrix.py +316 -222
  30. exonware/xwnode/edges/strategies/base.py +1 -1
  31. exonware/xwnode/edges/strategies/{edge_bidir_wrapper.py → bidir_wrapper.py} +45 -4
  32. exonware/xwnode/edges/strategies/bitemporal.py +520 -0
  33. exonware/xwnode/edges/strategies/{edge_block_adj_matrix.py → block_adj_matrix.py} +77 -6
  34. exonware/xwnode/edges/strategies/bv_graph.py +664 -0
  35. exonware/xwnode/edges/strategies/compressed_graph.py +217 -0
  36. exonware/xwnode/edges/strategies/{edge_coo.py → coo.py} +46 -4
  37. exonware/xwnode/edges/strategies/{edge_csc.py → csc.py} +45 -4
  38. exonware/xwnode/edges/strategies/{edge_csr.py → csr.py} +94 -12
  39. exonware/xwnode/edges/strategies/{edge_dynamic_adj_list.py → dynamic_adj_list.py} +46 -4
  40. exonware/xwnode/edges/strategies/edge_list.py +168 -0
  41. exonware/xwnode/edges/strategies/edge_property_store.py +2 -2
  42. exonware/xwnode/edges/strategies/euler_tour.py +560 -0
  43. exonware/xwnode/edges/strategies/{edge_flow_network.py → flow_network.py} +2 -2
  44. exonware/xwnode/edges/strategies/graphblas.py +449 -0
  45. exonware/xwnode/edges/strategies/hnsw.py +637 -0
  46. exonware/xwnode/edges/strategies/hop2_labels.py +467 -0
  47. exonware/xwnode/edges/strategies/{edge_hyperedge_set.py → hyperedge_set.py} +2 -2
  48. exonware/xwnode/edges/strategies/incidence_matrix.py +250 -0
  49. exonware/xwnode/edges/strategies/k2_tree.py +613 -0
  50. exonware/xwnode/edges/strategies/link_cut.py +626 -0
  51. exonware/xwnode/edges/strategies/multiplex.py +532 -0
  52. exonware/xwnode/edges/strategies/{edge_neural_graph.py → neural_graph.py} +2 -2
  53. exonware/xwnode/edges/strategies/{edge_octree.py → octree.py} +69 -11
  54. exonware/xwnode/edges/strategies/{edge_quadtree.py → quadtree.py} +66 -10
  55. exonware/xwnode/edges/strategies/roaring_adj.py +438 -0
  56. exonware/xwnode/edges/strategies/{edge_rtree.py → rtree.py} +43 -5
  57. exonware/xwnode/edges/strategies/{edge_temporal_edgeset.py → temporal_edgeset.py} +24 -5
  58. exonware/xwnode/edges/strategies/{edge_tree_graph_basic.py → tree_graph_basic.py} +78 -7
  59. exonware/xwnode/edges/strategies/{edge_weighted_graph.py → weighted_graph.py} +188 -10
  60. exonware/xwnode/errors.py +3 -6
  61. exonware/xwnode/facade.py +20 -20
  62. exonware/xwnode/nodes/strategies/__init__.py +29 -9
  63. exonware/xwnode/nodes/strategies/adjacency_list.py +650 -177
  64. exonware/xwnode/nodes/strategies/aho_corasick.py +358 -183
  65. exonware/xwnode/nodes/strategies/array_list.py +36 -3
  66. exonware/xwnode/nodes/strategies/art.py +581 -0
  67. exonware/xwnode/nodes/strategies/{node_avl_tree.py → avl_tree.py} +77 -6
  68. exonware/xwnode/nodes/strategies/{node_b_plus_tree.py → b_plus_tree.py} +81 -40
  69. exonware/xwnode/nodes/strategies/{node_btree.py → b_tree.py} +79 -9
  70. exonware/xwnode/nodes/strategies/base.py +469 -98
  71. exonware/xwnode/nodes/strategies/{node_bitmap.py → bitmap.py} +12 -12
  72. exonware/xwnode/nodes/strategies/{node_bitset_dynamic.py → bitset_dynamic.py} +11 -11
  73. exonware/xwnode/nodes/strategies/{node_bloom_filter.py → bloom_filter.py} +15 -2
  74. exonware/xwnode/nodes/strategies/bloomier_filter.py +519 -0
  75. exonware/xwnode/nodes/strategies/bw_tree.py +531 -0
  76. exonware/xwnode/nodes/strategies/contracts.py +1 -1
  77. exonware/xwnode/nodes/strategies/{node_count_min_sketch.py → count_min_sketch.py} +3 -2
  78. exonware/xwnode/nodes/strategies/{node_cow_tree.py → cow_tree.py} +135 -13
  79. exonware/xwnode/nodes/strategies/crdt_map.py +629 -0
  80. exonware/xwnode/nodes/strategies/{node_cuckoo_hash.py → cuckoo_hash.py} +2 -2
  81. exonware/xwnode/nodes/strategies/{node_xdata_optimized.py → data_interchange_optimized.py} +21 -4
  82. exonware/xwnode/nodes/strategies/dawg.py +876 -0
  83. exonware/xwnode/nodes/strategies/deque.py +321 -153
  84. exonware/xwnode/nodes/strategies/extendible_hash.py +93 -0
  85. exonware/xwnode/nodes/strategies/{node_fenwick_tree.py → fenwick_tree.py} +111 -19
  86. exonware/xwnode/nodes/strategies/hamt.py +403 -0
  87. exonware/xwnode/nodes/strategies/hash_map.py +354 -67
  88. exonware/xwnode/nodes/strategies/heap.py +105 -5
  89. exonware/xwnode/nodes/strategies/hopscotch_hash.py +525 -0
  90. exonware/xwnode/nodes/strategies/{node_hyperloglog.py → hyperloglog.py} +6 -5
  91. exonware/xwnode/nodes/strategies/interval_tree.py +742 -0
  92. exonware/xwnode/nodes/strategies/kd_tree.py +703 -0
  93. exonware/xwnode/nodes/strategies/learned_index.py +533 -0
  94. exonware/xwnode/nodes/strategies/linear_hash.py +93 -0
  95. exonware/xwnode/nodes/strategies/linked_list.py +316 -119
  96. exonware/xwnode/nodes/strategies/{node_lsm_tree.py → lsm_tree.py} +219 -15
  97. exonware/xwnode/nodes/strategies/masstree.py +130 -0
  98. exonware/xwnode/nodes/strategies/{node_persistent_tree.py → persistent_tree.py} +149 -9
  99. exonware/xwnode/nodes/strategies/priority_queue.py +544 -132
  100. exonware/xwnode/nodes/strategies/queue.py +249 -120
  101. exonware/xwnode/nodes/strategies/{node_red_black_tree.py → red_black_tree.py} +183 -72
  102. exonware/xwnode/nodes/strategies/{node_roaring_bitmap.py → roaring_bitmap.py} +19 -6
  103. exonware/xwnode/nodes/strategies/rope.py +717 -0
  104. exonware/xwnode/nodes/strategies/{node_segment_tree.py → segment_tree.py} +106 -106
  105. exonware/xwnode/nodes/strategies/{node_set_hash.py → set_hash.py} +30 -29
  106. exonware/xwnode/nodes/strategies/{node_skip_list.py → skip_list.py} +74 -6
  107. exonware/xwnode/nodes/strategies/sparse_matrix.py +427 -131
  108. exonware/xwnode/nodes/strategies/{node_splay_tree.py → splay_tree.py} +55 -6
  109. exonware/xwnode/nodes/strategies/stack.py +244 -112
  110. exonware/xwnode/nodes/strategies/{node_suffix_array.py → suffix_array.py} +5 -1
  111. exonware/xwnode/nodes/strategies/t_tree.py +94 -0
  112. exonware/xwnode/nodes/strategies/{node_treap.py → treap.py} +75 -6
  113. exonware/xwnode/nodes/strategies/{node_tree_graph_hybrid.py → tree_graph_hybrid.py} +46 -5
  114. exonware/xwnode/nodes/strategies/trie.py +153 -9
  115. exonware/xwnode/nodes/strategies/union_find.py +111 -5
  116. exonware/xwnode/nodes/strategies/veb_tree.py +856 -0
  117. exonware/xwnode/strategies/__init__.py +5 -51
  118. exonware/xwnode/version.py +3 -3
  119. {exonware_xwnode-0.0.1.22.dist-info → exonware_xwnode-0.0.1.23.dist-info}/METADATA +23 -3
  120. exonware_xwnode-0.0.1.23.dist-info/RECORD +130 -0
  121. exonware/xwnode/edges/strategies/edge_adj_list.py +0 -353
  122. exonware/xwnode/edges/strategies/edge_adj_matrix.py +0 -445
  123. exonware/xwnode/nodes/strategies/_base_node.py +0 -307
  124. exonware/xwnode/nodes/strategies/node_aho_corasick.py +0 -525
  125. exonware/xwnode/nodes/strategies/node_array_list.py +0 -179
  126. exonware/xwnode/nodes/strategies/node_hash_map.py +0 -273
  127. exonware/xwnode/nodes/strategies/node_heap.py +0 -196
  128. exonware/xwnode/nodes/strategies/node_linked_list.py +0 -413
  129. exonware/xwnode/nodes/strategies/node_trie.py +0 -257
  130. exonware/xwnode/nodes/strategies/node_union_find.py +0 -192
  131. exonware/xwnode/queries/executors/__init__.py +0 -47
  132. exonware/xwnode/queries/executors/advanced/__init__.py +0 -37
  133. exonware/xwnode/queries/executors/advanced/aggregate_executor.py +0 -50
  134. exonware/xwnode/queries/executors/advanced/ask_executor.py +0 -50
  135. exonware/xwnode/queries/executors/advanced/construct_executor.py +0 -50
  136. exonware/xwnode/queries/executors/advanced/describe_executor.py +0 -50
  137. exonware/xwnode/queries/executors/advanced/for_loop_executor.py +0 -50
  138. exonware/xwnode/queries/executors/advanced/foreach_executor.py +0 -50
  139. exonware/xwnode/queries/executors/advanced/join_executor.py +0 -50
  140. exonware/xwnode/queries/executors/advanced/let_executor.py +0 -50
  141. exonware/xwnode/queries/executors/advanced/mutation_executor.py +0 -50
  142. exonware/xwnode/queries/executors/advanced/options_executor.py +0 -50
  143. exonware/xwnode/queries/executors/advanced/pipe_executor.py +0 -50
  144. exonware/xwnode/queries/executors/advanced/subscribe_executor.py +0 -50
  145. exonware/xwnode/queries/executors/advanced/subscription_executor.py +0 -50
  146. exonware/xwnode/queries/executors/advanced/union_executor.py +0 -50
  147. exonware/xwnode/queries/executors/advanced/window_executor.py +0 -51
  148. exonware/xwnode/queries/executors/advanced/with_cte_executor.py +0 -50
  149. exonware/xwnode/queries/executors/aggregation/__init__.py +0 -21
  150. exonware/xwnode/queries/executors/aggregation/avg_executor.py +0 -50
  151. exonware/xwnode/queries/executors/aggregation/count_executor.py +0 -38
  152. exonware/xwnode/queries/executors/aggregation/distinct_executor.py +0 -50
  153. exonware/xwnode/queries/executors/aggregation/group_executor.py +0 -50
  154. exonware/xwnode/queries/executors/aggregation/having_executor.py +0 -50
  155. exonware/xwnode/queries/executors/aggregation/max_executor.py +0 -50
  156. exonware/xwnode/queries/executors/aggregation/min_executor.py +0 -50
  157. exonware/xwnode/queries/executors/aggregation/sum_executor.py +0 -50
  158. exonware/xwnode/queries/executors/aggregation/summarize_executor.py +0 -50
  159. exonware/xwnode/queries/executors/array/__init__.py +0 -9
  160. exonware/xwnode/queries/executors/array/indexing_executor.py +0 -51
  161. exonware/xwnode/queries/executors/array/slicing_executor.py +0 -51
  162. exonware/xwnode/queries/executors/base.py +0 -257
  163. exonware/xwnode/queries/executors/capability_checker.py +0 -204
  164. exonware/xwnode/queries/executors/contracts.py +0 -166
  165. exonware/xwnode/queries/executors/core/__init__.py +0 -17
  166. exonware/xwnode/queries/executors/core/create_executor.py +0 -96
  167. exonware/xwnode/queries/executors/core/delete_executor.py +0 -99
  168. exonware/xwnode/queries/executors/core/drop_executor.py +0 -100
  169. exonware/xwnode/queries/executors/core/insert_executor.py +0 -39
  170. exonware/xwnode/queries/executors/core/select_executor.py +0 -152
  171. exonware/xwnode/queries/executors/core/update_executor.py +0 -102
  172. exonware/xwnode/queries/executors/data/__init__.py +0 -13
  173. exonware/xwnode/queries/executors/data/alter_executor.py +0 -50
  174. exonware/xwnode/queries/executors/data/load_executor.py +0 -50
  175. exonware/xwnode/queries/executors/data/merge_executor.py +0 -50
  176. exonware/xwnode/queries/executors/data/store_executor.py +0 -50
  177. exonware/xwnode/queries/executors/defs.py +0 -93
  178. exonware/xwnode/queries/executors/engine.py +0 -221
  179. exonware/xwnode/queries/executors/errors.py +0 -68
  180. exonware/xwnode/queries/executors/filtering/__init__.py +0 -25
  181. exonware/xwnode/queries/executors/filtering/between_executor.py +0 -80
  182. exonware/xwnode/queries/executors/filtering/filter_executor.py +0 -79
  183. exonware/xwnode/queries/executors/filtering/has_executor.py +0 -70
  184. exonware/xwnode/queries/executors/filtering/in_executor.py +0 -70
  185. exonware/xwnode/queries/executors/filtering/like_executor.py +0 -76
  186. exonware/xwnode/queries/executors/filtering/optional_executor.py +0 -76
  187. exonware/xwnode/queries/executors/filtering/range_executor.py +0 -80
  188. exonware/xwnode/queries/executors/filtering/term_executor.py +0 -77
  189. exonware/xwnode/queries/executors/filtering/values_executor.py +0 -71
  190. exonware/xwnode/queries/executors/filtering/where_executor.py +0 -44
  191. exonware/xwnode/queries/executors/graph/__init__.py +0 -15
  192. exonware/xwnode/queries/executors/graph/in_traverse_executor.py +0 -51
  193. exonware/xwnode/queries/executors/graph/match_executor.py +0 -51
  194. exonware/xwnode/queries/executors/graph/out_executor.py +0 -51
  195. exonware/xwnode/queries/executors/graph/path_executor.py +0 -51
  196. exonware/xwnode/queries/executors/graph/return_executor.py +0 -51
  197. exonware/xwnode/queries/executors/ordering/__init__.py +0 -9
  198. exonware/xwnode/queries/executors/ordering/by_executor.py +0 -50
  199. exonware/xwnode/queries/executors/ordering/order_executor.py +0 -51
  200. exonware/xwnode/queries/executors/projection/__init__.py +0 -9
  201. exonware/xwnode/queries/executors/projection/extend_executor.py +0 -50
  202. exonware/xwnode/queries/executors/projection/project_executor.py +0 -50
  203. exonware/xwnode/queries/executors/registry.py +0 -173
  204. exonware/xwnode/queries/parsers/__init__.py +0 -26
  205. exonware/xwnode/queries/parsers/base.py +0 -86
  206. exonware/xwnode/queries/parsers/contracts.py +0 -46
  207. exonware/xwnode/queries/parsers/errors.py +0 -53
  208. exonware/xwnode/queries/parsers/sql_param_extractor.py +0 -318
  209. exonware/xwnode/queries/strategies/__init__.py +0 -24
  210. exonware/xwnode/queries/strategies/base.py +0 -236
  211. exonware/xwnode/queries/strategies/cql.py +0 -201
  212. exonware/xwnode/queries/strategies/cypher.py +0 -181
  213. exonware/xwnode/queries/strategies/datalog.py +0 -70
  214. exonware/xwnode/queries/strategies/elastic_dsl.py +0 -70
  215. exonware/xwnode/queries/strategies/eql.py +0 -70
  216. exonware/xwnode/queries/strategies/flux.py +0 -70
  217. exonware/xwnode/queries/strategies/gql.py +0 -70
  218. exonware/xwnode/queries/strategies/graphql.py +0 -240
  219. exonware/xwnode/queries/strategies/gremlin.py +0 -181
  220. exonware/xwnode/queries/strategies/hiveql.py +0 -214
  221. exonware/xwnode/queries/strategies/hql.py +0 -70
  222. exonware/xwnode/queries/strategies/jmespath.py +0 -219
  223. exonware/xwnode/queries/strategies/jq.py +0 -66
  224. exonware/xwnode/queries/strategies/json_query.py +0 -66
  225. exonware/xwnode/queries/strategies/jsoniq.py +0 -248
  226. exonware/xwnode/queries/strategies/kql.py +0 -70
  227. exonware/xwnode/queries/strategies/linq.py +0 -238
  228. exonware/xwnode/queries/strategies/logql.py +0 -70
  229. exonware/xwnode/queries/strategies/mql.py +0 -68
  230. exonware/xwnode/queries/strategies/n1ql.py +0 -210
  231. exonware/xwnode/queries/strategies/partiql.py +0 -70
  232. exonware/xwnode/queries/strategies/pig.py +0 -215
  233. exonware/xwnode/queries/strategies/promql.py +0 -70
  234. exonware/xwnode/queries/strategies/sparql.py +0 -220
  235. exonware/xwnode/queries/strategies/sql.py +0 -275
  236. exonware/xwnode/queries/strategies/xml_query.py +0 -66
  237. exonware/xwnode/queries/strategies/xpath.py +0 -223
  238. exonware/xwnode/queries/strategies/xquery.py +0 -258
  239. exonware/xwnode/queries/strategies/xwnode_executor.py +0 -332
  240. exonware/xwnode/queries/strategies/xwquery.py +0 -456
  241. exonware_xwnode-0.0.1.22.dist-info/RECORD +0 -214
  242. /exonware/xwnode/nodes/strategies/{node_ordered_map.py → ordered_map.py} +0 -0
  243. /exonware/xwnode/nodes/strategies/{node_ordered_map_balanced.py → ordered_map_balanced.py} +0 -0
  244. /exonware/xwnode/nodes/strategies/{node_patricia.py → patricia.py} +0 -0
  245. /exonware/xwnode/nodes/strategies/{node_radix_trie.py → radix_trie.py} +0 -0
  246. /exonware/xwnode/nodes/strategies/{node_set_tree.py → set_tree.py} +0 -0
  247. {exonware_xwnode-0.0.1.22.dist-info → exonware_xwnode-0.0.1.23.dist-info}/WHEEL +0 -0
  248. {exonware_xwnode-0.0.1.22.dist-info → exonware_xwnode-0.0.1.23.dist-info}/licenses/LICENSE +0 -0
@@ -1,223 +0,0 @@
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.22
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
@@ -1,258 +0,0 @@
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.22
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