exonware-xwnode 0.0.1.21__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.
- exonware/__init__.py +8 -1
- exonware/xwnode/__init__.py +18 -5
- exonware/xwnode/add_strategy_types.py +165 -0
- exonware/xwnode/base.py +7 -5
- exonware/xwnode/common/__init__.py +1 -1
- exonware/xwnode/common/graph/__init__.py +30 -0
- exonware/xwnode/common/graph/caching.py +131 -0
- exonware/xwnode/common/graph/contracts.py +100 -0
- exonware/xwnode/common/graph/errors.py +44 -0
- exonware/xwnode/common/graph/indexing.py +260 -0
- exonware/xwnode/common/graph/manager.py +568 -0
- exonware/xwnode/common/management/__init__.py +3 -5
- exonware/xwnode/common/management/manager.py +9 -9
- exonware/xwnode/common/management/migration.py +6 -6
- exonware/xwnode/common/monitoring/__init__.py +3 -5
- exonware/xwnode/common/monitoring/metrics.py +7 -3
- exonware/xwnode/common/monitoring/pattern_detector.py +2 -2
- exonware/xwnode/common/monitoring/performance_monitor.py +6 -2
- exonware/xwnode/common/patterns/__init__.py +3 -5
- exonware/xwnode/common/patterns/advisor.py +1 -1
- exonware/xwnode/common/patterns/flyweight.py +6 -2
- exonware/xwnode/common/patterns/registry.py +203 -184
- exonware/xwnode/common/utils/__init__.py +25 -11
- exonware/xwnode/common/utils/simple.py +1 -1
- exonware/xwnode/config.py +3 -8
- exonware/xwnode/contracts.py +4 -105
- exonware/xwnode/defs.py +413 -159
- exonware/xwnode/edges/strategies/__init__.py +86 -4
- exonware/xwnode/edges/strategies/_base_edge.py +2 -2
- exonware/xwnode/edges/strategies/adj_list.py +287 -121
- exonware/xwnode/edges/strategies/adj_matrix.py +316 -222
- exonware/xwnode/edges/strategies/base.py +1 -1
- exonware/xwnode/edges/strategies/{edge_bidir_wrapper.py → bidir_wrapper.py} +45 -4
- exonware/xwnode/edges/strategies/bitemporal.py +520 -0
- exonware/xwnode/edges/strategies/{edge_block_adj_matrix.py → block_adj_matrix.py} +77 -6
- exonware/xwnode/edges/strategies/bv_graph.py +664 -0
- exonware/xwnode/edges/strategies/compressed_graph.py +217 -0
- exonware/xwnode/edges/strategies/{edge_coo.py → coo.py} +46 -4
- exonware/xwnode/edges/strategies/{edge_csc.py → csc.py} +45 -4
- exonware/xwnode/edges/strategies/{edge_csr.py → csr.py} +94 -12
- exonware/xwnode/edges/strategies/{edge_dynamic_adj_list.py → dynamic_adj_list.py} +46 -4
- exonware/xwnode/edges/strategies/edge_list.py +168 -0
- exonware/xwnode/edges/strategies/edge_property_store.py +2 -2
- exonware/xwnode/edges/strategies/euler_tour.py +560 -0
- exonware/xwnode/edges/strategies/{edge_flow_network.py → flow_network.py} +2 -2
- exonware/xwnode/edges/strategies/graphblas.py +449 -0
- exonware/xwnode/edges/strategies/hnsw.py +637 -0
- exonware/xwnode/edges/strategies/hop2_labels.py +467 -0
- exonware/xwnode/edges/strategies/{edge_hyperedge_set.py → hyperedge_set.py} +2 -2
- exonware/xwnode/edges/strategies/incidence_matrix.py +250 -0
- exonware/xwnode/edges/strategies/k2_tree.py +613 -0
- exonware/xwnode/edges/strategies/link_cut.py +626 -0
- exonware/xwnode/edges/strategies/multiplex.py +532 -0
- exonware/xwnode/edges/strategies/{edge_neural_graph.py → neural_graph.py} +2 -2
- exonware/xwnode/edges/strategies/{edge_octree.py → octree.py} +69 -11
- exonware/xwnode/edges/strategies/{edge_quadtree.py → quadtree.py} +66 -10
- exonware/xwnode/edges/strategies/roaring_adj.py +438 -0
- exonware/xwnode/edges/strategies/{edge_rtree.py → rtree.py} +43 -5
- exonware/xwnode/edges/strategies/{edge_temporal_edgeset.py → temporal_edgeset.py} +24 -5
- exonware/xwnode/edges/strategies/{edge_tree_graph_basic.py → tree_graph_basic.py} +78 -7
- exonware/xwnode/edges/strategies/{edge_weighted_graph.py → weighted_graph.py} +188 -10
- exonware/xwnode/errors.py +3 -6
- exonware/xwnode/facade.py +20 -20
- exonware/xwnode/nodes/strategies/__init__.py +29 -9
- exonware/xwnode/nodes/strategies/adjacency_list.py +650 -177
- exonware/xwnode/nodes/strategies/aho_corasick.py +358 -183
- exonware/xwnode/nodes/strategies/array_list.py +36 -3
- exonware/xwnode/nodes/strategies/art.py +581 -0
- exonware/xwnode/nodes/strategies/{node_avl_tree.py → avl_tree.py} +77 -6
- exonware/xwnode/nodes/strategies/{node_b_plus_tree.py → b_plus_tree.py} +81 -40
- exonware/xwnode/nodes/strategies/{node_btree.py → b_tree.py} +79 -9
- exonware/xwnode/nodes/strategies/base.py +469 -98
- exonware/xwnode/nodes/strategies/{node_bitmap.py → bitmap.py} +12 -12
- exonware/xwnode/nodes/strategies/{node_bitset_dynamic.py → bitset_dynamic.py} +11 -11
- exonware/xwnode/nodes/strategies/{node_bloom_filter.py → bloom_filter.py} +15 -2
- exonware/xwnode/nodes/strategies/bloomier_filter.py +519 -0
- exonware/xwnode/nodes/strategies/bw_tree.py +531 -0
- exonware/xwnode/nodes/strategies/contracts.py +1 -1
- exonware/xwnode/nodes/strategies/{node_count_min_sketch.py → count_min_sketch.py} +3 -2
- exonware/xwnode/nodes/strategies/{node_cow_tree.py → cow_tree.py} +135 -13
- exonware/xwnode/nodes/strategies/crdt_map.py +629 -0
- exonware/xwnode/nodes/strategies/{node_cuckoo_hash.py → cuckoo_hash.py} +2 -2
- exonware/xwnode/nodes/strategies/{node_xdata_optimized.py → data_interchange_optimized.py} +21 -4
- exonware/xwnode/nodes/strategies/dawg.py +876 -0
- exonware/xwnode/nodes/strategies/deque.py +321 -153
- exonware/xwnode/nodes/strategies/extendible_hash.py +93 -0
- exonware/xwnode/nodes/strategies/{node_fenwick_tree.py → fenwick_tree.py} +111 -19
- exonware/xwnode/nodes/strategies/hamt.py +403 -0
- exonware/xwnode/nodes/strategies/hash_map.py +354 -67
- exonware/xwnode/nodes/strategies/heap.py +105 -5
- exonware/xwnode/nodes/strategies/hopscotch_hash.py +525 -0
- exonware/xwnode/nodes/strategies/{node_hyperloglog.py → hyperloglog.py} +6 -5
- exonware/xwnode/nodes/strategies/interval_tree.py +742 -0
- exonware/xwnode/nodes/strategies/kd_tree.py +703 -0
- exonware/xwnode/nodes/strategies/learned_index.py +533 -0
- exonware/xwnode/nodes/strategies/linear_hash.py +93 -0
- exonware/xwnode/nodes/strategies/linked_list.py +316 -119
- exonware/xwnode/nodes/strategies/{node_lsm_tree.py → lsm_tree.py} +219 -15
- exonware/xwnode/nodes/strategies/masstree.py +130 -0
- exonware/xwnode/nodes/strategies/{node_persistent_tree.py → persistent_tree.py} +149 -9
- exonware/xwnode/nodes/strategies/priority_queue.py +544 -132
- exonware/xwnode/nodes/strategies/queue.py +249 -120
- exonware/xwnode/nodes/strategies/{node_red_black_tree.py → red_black_tree.py} +183 -72
- exonware/xwnode/nodes/strategies/{node_roaring_bitmap.py → roaring_bitmap.py} +19 -6
- exonware/xwnode/nodes/strategies/rope.py +717 -0
- exonware/xwnode/nodes/strategies/{node_segment_tree.py → segment_tree.py} +106 -106
- exonware/xwnode/nodes/strategies/{node_set_hash.py → set_hash.py} +30 -29
- exonware/xwnode/nodes/strategies/{node_skip_list.py → skip_list.py} +74 -6
- exonware/xwnode/nodes/strategies/sparse_matrix.py +427 -131
- exonware/xwnode/nodes/strategies/{node_splay_tree.py → splay_tree.py} +55 -6
- exonware/xwnode/nodes/strategies/stack.py +244 -112
- exonware/xwnode/nodes/strategies/{node_suffix_array.py → suffix_array.py} +5 -1
- exonware/xwnode/nodes/strategies/t_tree.py +94 -0
- exonware/xwnode/nodes/strategies/{node_treap.py → treap.py} +75 -6
- exonware/xwnode/nodes/strategies/{node_tree_graph_hybrid.py → tree_graph_hybrid.py} +46 -5
- exonware/xwnode/nodes/strategies/trie.py +153 -9
- exonware/xwnode/nodes/strategies/union_find.py +111 -5
- exonware/xwnode/nodes/strategies/veb_tree.py +856 -0
- exonware/xwnode/strategies/__init__.py +5 -51
- exonware/xwnode/version.py +3 -3
- {exonware_xwnode-0.0.1.21.dist-info → exonware_xwnode-0.0.1.23.dist-info}/METADATA +23 -3
- exonware_xwnode-0.0.1.23.dist-info/RECORD +130 -0
- exonware/xwnode/edges/strategies/edge_adj_list.py +0 -353
- exonware/xwnode/edges/strategies/edge_adj_matrix.py +0 -445
- exonware/xwnode/nodes/strategies/_base_node.py +0 -307
- exonware/xwnode/nodes/strategies/node_aho_corasick.py +0 -525
- exonware/xwnode/nodes/strategies/node_array_list.py +0 -179
- exonware/xwnode/nodes/strategies/node_hash_map.py +0 -273
- exonware/xwnode/nodes/strategies/node_heap.py +0 -196
- exonware/xwnode/nodes/strategies/node_linked_list.py +0 -413
- exonware/xwnode/nodes/strategies/node_trie.py +0 -257
- exonware/xwnode/nodes/strategies/node_union_find.py +0 -192
- exonware/xwnode/queries/executors/__init__.py +0 -47
- exonware/xwnode/queries/executors/advanced/__init__.py +0 -37
- exonware/xwnode/queries/executors/advanced/aggregate_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/ask_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/construct_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/describe_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/for_loop_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/foreach_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/join_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/let_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/mutation_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/options_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/pipe_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/subscribe_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/subscription_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/union_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/window_executor.py +0 -51
- exonware/xwnode/queries/executors/advanced/with_cte_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/__init__.py +0 -21
- exonware/xwnode/queries/executors/aggregation/avg_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/count_executor.py +0 -38
- exonware/xwnode/queries/executors/aggregation/distinct_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/group_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/having_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/max_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/min_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/sum_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/summarize_executor.py +0 -50
- exonware/xwnode/queries/executors/array/__init__.py +0 -9
- exonware/xwnode/queries/executors/array/indexing_executor.py +0 -51
- exonware/xwnode/queries/executors/array/slicing_executor.py +0 -51
- exonware/xwnode/queries/executors/base.py +0 -257
- exonware/xwnode/queries/executors/capability_checker.py +0 -204
- exonware/xwnode/queries/executors/contracts.py +0 -166
- exonware/xwnode/queries/executors/core/__init__.py +0 -17
- exonware/xwnode/queries/executors/core/create_executor.py +0 -96
- exonware/xwnode/queries/executors/core/delete_executor.py +0 -99
- exonware/xwnode/queries/executors/core/drop_executor.py +0 -100
- exonware/xwnode/queries/executors/core/insert_executor.py +0 -39
- exonware/xwnode/queries/executors/core/select_executor.py +0 -152
- exonware/xwnode/queries/executors/core/update_executor.py +0 -102
- exonware/xwnode/queries/executors/data/__init__.py +0 -13
- exonware/xwnode/queries/executors/data/alter_executor.py +0 -50
- exonware/xwnode/queries/executors/data/load_executor.py +0 -50
- exonware/xwnode/queries/executors/data/merge_executor.py +0 -50
- exonware/xwnode/queries/executors/data/store_executor.py +0 -50
- exonware/xwnode/queries/executors/defs.py +0 -93
- exonware/xwnode/queries/executors/engine.py +0 -221
- exonware/xwnode/queries/executors/errors.py +0 -68
- exonware/xwnode/queries/executors/filtering/__init__.py +0 -25
- exonware/xwnode/queries/executors/filtering/between_executor.py +0 -80
- exonware/xwnode/queries/executors/filtering/filter_executor.py +0 -79
- exonware/xwnode/queries/executors/filtering/has_executor.py +0 -70
- exonware/xwnode/queries/executors/filtering/in_executor.py +0 -70
- exonware/xwnode/queries/executors/filtering/like_executor.py +0 -76
- exonware/xwnode/queries/executors/filtering/optional_executor.py +0 -76
- exonware/xwnode/queries/executors/filtering/range_executor.py +0 -80
- exonware/xwnode/queries/executors/filtering/term_executor.py +0 -77
- exonware/xwnode/queries/executors/filtering/values_executor.py +0 -71
- exonware/xwnode/queries/executors/filtering/where_executor.py +0 -44
- exonware/xwnode/queries/executors/graph/__init__.py +0 -15
- exonware/xwnode/queries/executors/graph/in_traverse_executor.py +0 -51
- exonware/xwnode/queries/executors/graph/match_executor.py +0 -51
- exonware/xwnode/queries/executors/graph/out_executor.py +0 -51
- exonware/xwnode/queries/executors/graph/path_executor.py +0 -51
- exonware/xwnode/queries/executors/graph/return_executor.py +0 -51
- exonware/xwnode/queries/executors/ordering/__init__.py +0 -9
- exonware/xwnode/queries/executors/ordering/by_executor.py +0 -50
- exonware/xwnode/queries/executors/ordering/order_executor.py +0 -51
- exonware/xwnode/queries/executors/projection/__init__.py +0 -9
- exonware/xwnode/queries/executors/projection/extend_executor.py +0 -50
- exonware/xwnode/queries/executors/projection/project_executor.py +0 -50
- exonware/xwnode/queries/executors/registry.py +0 -173
- exonware/xwnode/queries/parsers/__init__.py +0 -26
- exonware/xwnode/queries/parsers/base.py +0 -86
- exonware/xwnode/queries/parsers/contracts.py +0 -46
- exonware/xwnode/queries/parsers/errors.py +0 -53
- exonware/xwnode/queries/parsers/sql_param_extractor.py +0 -318
- exonware/xwnode/queries/strategies/__init__.py +0 -24
- exonware/xwnode/queries/strategies/base.py +0 -236
- exonware/xwnode/queries/strategies/cql.py +0 -201
- exonware/xwnode/queries/strategies/cypher.py +0 -181
- exonware/xwnode/queries/strategies/datalog.py +0 -70
- exonware/xwnode/queries/strategies/elastic_dsl.py +0 -70
- exonware/xwnode/queries/strategies/eql.py +0 -70
- exonware/xwnode/queries/strategies/flux.py +0 -70
- exonware/xwnode/queries/strategies/gql.py +0 -70
- exonware/xwnode/queries/strategies/graphql.py +0 -240
- exonware/xwnode/queries/strategies/gremlin.py +0 -181
- exonware/xwnode/queries/strategies/hiveql.py +0 -214
- exonware/xwnode/queries/strategies/hql.py +0 -70
- exonware/xwnode/queries/strategies/jmespath.py +0 -219
- exonware/xwnode/queries/strategies/jq.py +0 -66
- exonware/xwnode/queries/strategies/json_query.py +0 -66
- exonware/xwnode/queries/strategies/jsoniq.py +0 -248
- exonware/xwnode/queries/strategies/kql.py +0 -70
- exonware/xwnode/queries/strategies/linq.py +0 -238
- exonware/xwnode/queries/strategies/logql.py +0 -70
- exonware/xwnode/queries/strategies/mql.py +0 -68
- exonware/xwnode/queries/strategies/n1ql.py +0 -210
- exonware/xwnode/queries/strategies/partiql.py +0 -70
- exonware/xwnode/queries/strategies/pig.py +0 -215
- exonware/xwnode/queries/strategies/promql.py +0 -70
- exonware/xwnode/queries/strategies/sparql.py +0 -220
- exonware/xwnode/queries/strategies/sql.py +0 -275
- exonware/xwnode/queries/strategies/xml_query.py +0 -66
- exonware/xwnode/queries/strategies/xpath.py +0 -223
- exonware/xwnode/queries/strategies/xquery.py +0 -258
- exonware/xwnode/queries/strategies/xwnode_executor.py +0 -332
- exonware/xwnode/queries/strategies/xwquery.py +0 -456
- exonware_xwnode-0.0.1.21.dist-info/RECORD +0 -214
- /exonware/xwnode/nodes/strategies/{node_ordered_map.py → ordered_map.py} +0 -0
- /exonware/xwnode/nodes/strategies/{node_ordered_map_balanced.py → ordered_map_balanced.py} +0 -0
- /exonware/xwnode/nodes/strategies/{node_patricia.py → patricia.py} +0 -0
- /exonware/xwnode/nodes/strategies/{node_radix_trie.py → radix_trie.py} +0 -0
- /exonware/xwnode/nodes/strategies/{node_set_tree.py → set_tree.py} +0 -0
- {exonware_xwnode-0.0.1.21.dist-info → exonware_xwnode-0.0.1.23.dist-info}/WHEEL +0 -0
- {exonware_xwnode-0.0.1.21.dist-info → exonware_xwnode-0.0.1.23.dist-info}/licenses/LICENSE +0 -0
@@ -1,318 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
#exonware/xwnode/src/exonware/xwnode/queries/parsers/sql_param_extractor.py
|
4
|
-
|
5
|
-
SQL Parameter Extractor
|
6
|
-
|
7
|
-
Extracts structured parameters from SQL-style queries.
|
8
|
-
Uses regex for simplicity - follows DEV_GUIDELINES.md.
|
9
|
-
|
10
|
-
Company: eXonware.com
|
11
|
-
Author: Eng. Muhammad AlShehri
|
12
|
-
Email: connect@exonware.com
|
13
|
-
Version: 0.0.1.21
|
14
|
-
Generation Date: 09-Oct-2025
|
15
|
-
"""
|
16
|
-
|
17
|
-
import re
|
18
|
-
from typing import Dict, Any, List, Union
|
19
|
-
|
20
|
-
from .base import AParamExtractor
|
21
|
-
from .errors import ParseError
|
22
|
-
|
23
|
-
|
24
|
-
class SQLParamExtractor(AParamExtractor):
|
25
|
-
"""
|
26
|
-
SQL parameter extractor using regex.
|
27
|
-
|
28
|
-
Extracts structured parameters from SQL queries for executor consumption.
|
29
|
-
Implements IParamExtractor interface per DEV_GUIDELINES.md.
|
30
|
-
"""
|
31
|
-
|
32
|
-
def extract_params(self, query: str, action_type: str) -> Dict[str, Any]:
|
33
|
-
"""
|
34
|
-
Extract parameters based on action type.
|
35
|
-
|
36
|
-
Args:
|
37
|
-
query: SQL query string
|
38
|
-
action_type: Type of action (SELECT, INSERT, etc.)
|
39
|
-
|
40
|
-
Returns:
|
41
|
-
Structured parameters dictionary
|
42
|
-
"""
|
43
|
-
# Route to appropriate extractor
|
44
|
-
extractors = {
|
45
|
-
'SELECT': self.extract_select_params,
|
46
|
-
'INSERT': self.extract_insert_params,
|
47
|
-
'UPDATE': self.extract_update_params,
|
48
|
-
'DELETE': self.extract_delete_params,
|
49
|
-
'WHERE': self.extract_where_params,
|
50
|
-
'COUNT': self.extract_count_params,
|
51
|
-
'GROUP': self.extract_group_by_params,
|
52
|
-
'ORDER': self.extract_order_by_params,
|
53
|
-
}
|
54
|
-
|
55
|
-
extractor = extractors.get(action_type)
|
56
|
-
if extractor:
|
57
|
-
return extractor(query)
|
58
|
-
|
59
|
-
# Fallback: return raw query
|
60
|
-
return {'raw': query}
|
61
|
-
|
62
|
-
def can_parse(self, query: str) -> bool:
|
63
|
-
"""Check if query looks like SQL."""
|
64
|
-
query_upper = query.upper()
|
65
|
-
sql_keywords = ['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'FROM', 'WHERE']
|
66
|
-
return any(kw in query_upper for kw in sql_keywords)
|
67
|
-
|
68
|
-
def extract_select_params(self, sql: str) -> Dict[str, Any]:
|
69
|
-
"""Extract SELECT statement parameters."""
|
70
|
-
params = {}
|
71
|
-
|
72
|
-
# Extract SELECT fields
|
73
|
-
select_match = re.search(r'SELECT\s+(.*?)\s+FROM', sql, re.IGNORECASE | re.DOTALL)
|
74
|
-
if select_match:
|
75
|
-
fields_str = select_match.group(1).strip()
|
76
|
-
params['fields'] = self._split_fields(fields_str)
|
77
|
-
else:
|
78
|
-
params['fields'] = ['*']
|
79
|
-
|
80
|
-
# Extract FROM table
|
81
|
-
from_match = re.search(r'FROM\s+(\w+)', sql, re.IGNORECASE)
|
82
|
-
if from_match:
|
83
|
-
params['from'] = from_match.group(1)
|
84
|
-
params['path'] = from_match.group(1) # Alias for compatibility
|
85
|
-
|
86
|
-
# Extract WHERE conditions
|
87
|
-
where_match = re.search(r'WHERE\s+(.+?)(?:ORDER|GROUP|LIMIT|$)', sql, re.IGNORECASE | re.DOTALL)
|
88
|
-
if where_match:
|
89
|
-
params['where'] = self._parse_where_condition(where_match.group(1).strip())
|
90
|
-
|
91
|
-
# Extract ORDER BY
|
92
|
-
order_match = re.search(r'ORDER\s+BY\s+(.*?)(?:LIMIT|$)', sql, re.IGNORECASE | re.DOTALL)
|
93
|
-
if order_match:
|
94
|
-
params['order_by'] = order_match.group(1).strip()
|
95
|
-
|
96
|
-
# Extract GROUP BY
|
97
|
-
group_match = re.search(r'GROUP\s+BY\s+(.*?)(?:HAVING|ORDER|LIMIT|$)', sql, re.IGNORECASE | re.DOTALL)
|
98
|
-
if group_match:
|
99
|
-
params['group_by'] = [f.strip() for f in group_match.group(1).split(',')]
|
100
|
-
|
101
|
-
# Extract LIMIT
|
102
|
-
limit_match = re.search(r'LIMIT\s+(\d+)', sql, re.IGNORECASE)
|
103
|
-
if limit_match:
|
104
|
-
params['limit'] = int(limit_match.group(1))
|
105
|
-
|
106
|
-
return params
|
107
|
-
|
108
|
-
def extract_insert_params(self, sql: str) -> Dict[str, Any]:
|
109
|
-
"""Extract INSERT statement parameters."""
|
110
|
-
params = {}
|
111
|
-
|
112
|
-
# INSERT INTO table VALUES {...}
|
113
|
-
into_match = re.search(r'INSERT\s+INTO\s+(\w+)', sql, re.IGNORECASE)
|
114
|
-
if into_match:
|
115
|
-
params['target'] = into_match.group(1)
|
116
|
-
|
117
|
-
# Extract VALUES
|
118
|
-
values_match = re.search(r'VALUES\s+(.+)', sql, re.IGNORECASE | re.DOTALL)
|
119
|
-
if values_match:
|
120
|
-
values_str = values_match.group(1).strip()
|
121
|
-
# Try to parse as JSON-like dict/list
|
122
|
-
try:
|
123
|
-
# Remove outer braces and parse key:value pairs
|
124
|
-
if values_str.startswith('{'):
|
125
|
-
params['values'] = self._parse_dict_literal(values_str)
|
126
|
-
elif values_str.startswith('('):
|
127
|
-
params['values'] = self._parse_tuple_literal(values_str)
|
128
|
-
except:
|
129
|
-
params['values'] = values_str
|
130
|
-
|
131
|
-
return params
|
132
|
-
|
133
|
-
def extract_update_params(self, sql: str) -> Dict[str, Any]:
|
134
|
-
"""Extract UPDATE statement parameters."""
|
135
|
-
params = {}
|
136
|
-
|
137
|
-
# UPDATE table SET ...
|
138
|
-
table_match = re.search(r'UPDATE\s+(\w+)', sql, re.IGNORECASE)
|
139
|
-
if table_match:
|
140
|
-
params['target'] = table_match.group(1)
|
141
|
-
|
142
|
-
# Extract SET clause
|
143
|
-
set_match = re.search(r'SET\s+(.+?)(?:WHERE|$)', sql, re.IGNORECASE | re.DOTALL)
|
144
|
-
if set_match:
|
145
|
-
params['values'] = self._parse_set_clause(set_match.group(1).strip())
|
146
|
-
|
147
|
-
# Extract WHERE
|
148
|
-
where_match = re.search(r'WHERE\s+(.+?)$', sql, re.IGNORECASE | re.DOTALL)
|
149
|
-
if where_match:
|
150
|
-
params['where'] = self._parse_where_condition(where_match.group(1).strip())
|
151
|
-
|
152
|
-
return params
|
153
|
-
|
154
|
-
def extract_delete_params(self, sql: str) -> Dict[str, Any]:
|
155
|
-
"""Extract DELETE statement parameters."""
|
156
|
-
params = {}
|
157
|
-
|
158
|
-
# DELETE FROM table
|
159
|
-
from_match = re.search(r'DELETE\s+FROM\s+(\w+)', sql, re.IGNORECASE)
|
160
|
-
if from_match:
|
161
|
-
params['target'] = from_match.group(1)
|
162
|
-
|
163
|
-
# Extract WHERE
|
164
|
-
where_match = re.search(r'WHERE\s+(.+?)$', sql, re.IGNORECASE | re.DOTALL)
|
165
|
-
if where_match:
|
166
|
-
params['where'] = self._parse_where_condition(where_match.group(1).strip())
|
167
|
-
|
168
|
-
return params
|
169
|
-
|
170
|
-
def extract_where_params(self, sql: str) -> Dict[str, Any]:
|
171
|
-
"""Extract WHERE clause parameters."""
|
172
|
-
# Extract just the condition part
|
173
|
-
where_match = re.search(r'WHERE\s+(.+?)(?:ORDER|GROUP|LIMIT|$)', sql, re.IGNORECASE | re.DOTALL)
|
174
|
-
if where_match:
|
175
|
-
return self._parse_where_condition(where_match.group(1).strip())
|
176
|
-
return {}
|
177
|
-
|
178
|
-
def extract_count_params(self, sql: str) -> Dict[str, Any]:
|
179
|
-
"""Extract COUNT parameters."""
|
180
|
-
params = {}
|
181
|
-
|
182
|
-
# COUNT(*) or COUNT(field)
|
183
|
-
count_match = re.search(r'COUNT\s*\(\s*([^)]+)\s*\)', sql, re.IGNORECASE)
|
184
|
-
if count_match:
|
185
|
-
field = count_match.group(1).strip()
|
186
|
-
params['field'] = field if field != '*' else None
|
187
|
-
|
188
|
-
# Extract FROM
|
189
|
-
from_match = re.search(r'FROM\s+(\w+)', sql, re.IGNORECASE)
|
190
|
-
if from_match:
|
191
|
-
params['from'] = from_match.group(1)
|
192
|
-
params['path'] = from_match.group(1)
|
193
|
-
|
194
|
-
# Extract WHERE
|
195
|
-
where_match = re.search(r'WHERE\s+(.+?)(?:ORDER|GROUP|LIMIT|$)', sql, re.IGNORECASE | re.DOTALL)
|
196
|
-
if where_match:
|
197
|
-
params['where'] = self._parse_where_condition(where_match.group(1).strip())
|
198
|
-
|
199
|
-
return params
|
200
|
-
|
201
|
-
def extract_group_by_params(self, sql: str) -> Dict[str, Any]:
|
202
|
-
"""Extract GROUP BY parameters."""
|
203
|
-
params = {}
|
204
|
-
|
205
|
-
# GROUP BY fields
|
206
|
-
group_match = re.search(r'GROUP\s+BY\s+(.*?)(?:HAVING|ORDER|LIMIT|$)', sql, re.IGNORECASE | re.DOTALL)
|
207
|
-
if group_match:
|
208
|
-
params['fields'] = [f.strip() for f in group_match.group(1).split(',')]
|
209
|
-
|
210
|
-
# Extract HAVING
|
211
|
-
having_match = re.search(r'HAVING\s+(.+?)(?:ORDER|LIMIT|$)', sql, re.IGNORECASE | re.DOTALL)
|
212
|
-
if having_match:
|
213
|
-
params['having'] = self._parse_where_condition(having_match.group(1).strip())
|
214
|
-
|
215
|
-
return params
|
216
|
-
|
217
|
-
def extract_order_by_params(self, sql: str) -> Dict[str, Any]:
|
218
|
-
"""Extract ORDER BY parameters."""
|
219
|
-
params = {}
|
220
|
-
|
221
|
-
# ORDER BY field ASC/DESC
|
222
|
-
order_match = re.search(r'ORDER\s+BY\s+(.*?)(?:LIMIT|$)', sql, re.IGNORECASE | re.DOTALL)
|
223
|
-
if order_match:
|
224
|
-
order_clause = order_match.group(1).strip()
|
225
|
-
|
226
|
-
# Parse: field ASC, field2 DESC
|
227
|
-
order_fields = []
|
228
|
-
for field_spec in order_clause.split(','):
|
229
|
-
field_spec = field_spec.strip()
|
230
|
-
if ' DESC' in field_spec.upper():
|
231
|
-
field = field_spec.upper().replace(' DESC', '').strip()
|
232
|
-
order_fields.append({'field': field, 'direction': 'DESC'})
|
233
|
-
elif ' ASC' in field_spec.upper():
|
234
|
-
field = field_spec.upper().replace(' ASC', '').strip()
|
235
|
-
order_fields.append({'field': field, 'direction': 'ASC'})
|
236
|
-
else:
|
237
|
-
order_fields.append({'field': field_spec, 'direction': 'ASC'})
|
238
|
-
|
239
|
-
params['fields'] = order_fields
|
240
|
-
|
241
|
-
return params
|
242
|
-
|
243
|
-
def _parse_where_condition(self, condition: str) -> Dict[str, Any]:
|
244
|
-
"""
|
245
|
-
Parse WHERE condition into structured format.
|
246
|
-
|
247
|
-
Supports: field operator value
|
248
|
-
Examples: age > 50, name = 'John', price >= 100
|
249
|
-
"""
|
250
|
-
condition = condition.strip()
|
251
|
-
|
252
|
-
# Check for operators in order of precedence
|
253
|
-
operators = ['>=', '<=', '!=', '<>', '>', '<', '=', 'LIKE', 'IN']
|
254
|
-
|
255
|
-
for op in operators:
|
256
|
-
# Case-insensitive for word operators
|
257
|
-
if op.isalpha():
|
258
|
-
pattern = rf'\s+{op}\s+'
|
259
|
-
match = re.search(pattern, condition, re.IGNORECASE)
|
260
|
-
if match:
|
261
|
-
field = condition[:match.start()].strip()
|
262
|
-
value = condition[match.end():].strip()
|
263
|
-
return {
|
264
|
-
'field': field,
|
265
|
-
'operator': op.upper(),
|
266
|
-
'value': self._parse_value(value) if op.upper() != 'IN' else self._parse_in_values(value)
|
267
|
-
}
|
268
|
-
else:
|
269
|
-
if op in condition:
|
270
|
-
parts = condition.split(op, 1)
|
271
|
-
if len(parts) == 2:
|
272
|
-
return {
|
273
|
-
'field': parts[0].strip(),
|
274
|
-
'operator': op,
|
275
|
-
'value': self._parse_value(parts[1].strip())
|
276
|
-
}
|
277
|
-
|
278
|
-
# Can't parse - return as expression
|
279
|
-
return {'expression': condition}
|
280
|
-
|
281
|
-
def _parse_in_values(self, values_str: str) -> List:
|
282
|
-
"""Parse IN clause values."""
|
283
|
-
# IN ['value1', 'value2'] or IN ('value1', 'value2')
|
284
|
-
values_str = values_str.strip().strip('[]()').strip()
|
285
|
-
values = [self._parse_value(v.strip()) for v in values_str.split(',')]
|
286
|
-
return values
|
287
|
-
|
288
|
-
def _parse_set_clause(self, set_str: str) -> Dict[str, Any]:
|
289
|
-
"""Parse SET clause in UPDATE."""
|
290
|
-
assignments = {}
|
291
|
-
|
292
|
-
# Split by comma
|
293
|
-
for assignment in set_str.split(','):
|
294
|
-
if '=' in assignment:
|
295
|
-
field, value = assignment.split('=', 1)
|
296
|
-
assignments[field.strip()] = self._parse_value(value.strip())
|
297
|
-
|
298
|
-
return assignments
|
299
|
-
|
300
|
-
def _parse_dict_literal(self, dict_str: str) -> Dict[str, Any]:
|
301
|
-
"""Parse dictionary literal from string."""
|
302
|
-
# Simple parser for {key: value, key2: value2}
|
303
|
-
dict_str = dict_str.strip('{}').strip()
|
304
|
-
result = {}
|
305
|
-
|
306
|
-
for pair in dict_str.split(','):
|
307
|
-
if ':' in pair:
|
308
|
-
key, value = pair.split(':', 1)
|
309
|
-
result[key.strip()] = self._parse_value(value.strip())
|
310
|
-
|
311
|
-
return result
|
312
|
-
|
313
|
-
def _parse_tuple_literal(self, tuple_str: str) -> List[Any]:
|
314
|
-
"""Parse tuple literal from string."""
|
315
|
-
# Simple parser for (value1, value2, value3)
|
316
|
-
tuple_str = tuple_str.strip('()').strip()
|
317
|
-
return [self._parse_value(v.strip()) for v in tuple_str.split(',')]
|
318
|
-
|
@@ -1,24 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Query Strategies Package
|
3
|
-
|
4
|
-
This package contains all query strategy implementations organized by type:
|
5
|
-
- Linear queries (index-based, value-based)
|
6
|
-
- Tree queries (key-based, range queries)
|
7
|
-
- Graph queries (path queries, neighbor queries)
|
8
|
-
|
9
|
-
Company: eXonware.com
|
10
|
-
Author: Eng. Muhammad AlShehri
|
11
|
-
Email: connect@exonware.com
|
12
|
-
Version: 0.0.1.21
|
13
|
-
Generation Date: January 2, 2025
|
14
|
-
"""
|
15
|
-
|
16
|
-
from .base import AQueryStrategy
|
17
|
-
from .xwquery_strategy import XWQueryScriptStrategy
|
18
|
-
from .xwnode_executor import XWNodeQueryActionExecutor
|
19
|
-
|
20
|
-
__all__ = [
|
21
|
-
'AQueryStrategy',
|
22
|
-
'XWQueryScriptStrategy',
|
23
|
-
'XWNodeQueryActionExecutor'
|
24
|
-
]
|
@@ -1,236 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
Query Strategy Base Classes
|
4
|
-
|
5
|
-
This module defines the abstract base classes for all query strategy implementations:
|
6
|
-
- AQueryStrategy: Base strategy for all query implementations
|
7
|
-
|
8
|
-
Company: eXonware.com
|
9
|
-
Author: Eng. Muhammad AlShehri
|
10
|
-
Email: connect@exonware.com
|
11
|
-
Version: 0.0.1.21
|
12
|
-
Generation Date: January 2, 2025
|
13
|
-
"""
|
14
|
-
|
15
|
-
from abc import ABC, abstractmethod
|
16
|
-
from typing import Any, Optional, List, Dict, Union, Type
|
17
|
-
from datetime import datetime
|
18
|
-
|
19
|
-
from ...contracts import iQuery, iQueryResult, IQueryStrategy, QueryMode, QueryTrait
|
20
|
-
from ...errors import XWNodeTypeError, XWNodeValueError
|
21
|
-
from ...base import XWNodeBase
|
22
|
-
|
23
|
-
|
24
|
-
class AQueryStrategy(IQueryStrategy):
|
25
|
-
"""Base strategy for all query implementations with XWQuery Script support."""
|
26
|
-
|
27
|
-
def __init__(self, **options):
|
28
|
-
"""Initialize query strategy."""
|
29
|
-
self._options = options
|
30
|
-
self._mode = options.get('mode', QueryMode.AUTO)
|
31
|
-
self._traits = options.get('traits', QueryTrait.NONE)
|
32
|
-
|
33
|
-
@abstractmethod
|
34
|
-
def execute(self, query: str, **kwargs) -> Any:
|
35
|
-
"""Execute query."""
|
36
|
-
pass
|
37
|
-
|
38
|
-
@abstractmethod
|
39
|
-
def validate_query(self, query: str) -> bool:
|
40
|
-
"""Validate query syntax."""
|
41
|
-
pass
|
42
|
-
|
43
|
-
@abstractmethod
|
44
|
-
def get_query_plan(self, query: str) -> Dict[str, Any]:
|
45
|
-
"""Get query execution plan."""
|
46
|
-
pass
|
47
|
-
|
48
|
-
def get_mode(self) -> QueryMode:
|
49
|
-
"""Get strategy mode."""
|
50
|
-
return self._mode
|
51
|
-
|
52
|
-
def get_traits(self) -> QueryTrait:
|
53
|
-
"""Get strategy traits."""
|
54
|
-
return self._traits
|
55
|
-
|
56
|
-
def to_native(self) -> 'XWQueryScriptStrategy':
|
57
|
-
"""Convert this strategy to XWQueryScriptStrategy using actions."""
|
58
|
-
from .xwquery_strategy import XWQueryScriptStrategy
|
59
|
-
return XWQueryScriptStrategy()
|
60
|
-
|
61
|
-
def to_actions_tree(self, query: str) -> XWNodeBase:
|
62
|
-
"""Convert query to actions tree - default implementation."""
|
63
|
-
script_strategy = self.to_native().from_format(query, self.get_query_type())
|
64
|
-
return script_strategy.get_actions_tree()
|
65
|
-
|
66
|
-
def from_actions_tree(self, actions_tree: XWNodeBase) -> str:
|
67
|
-
"""Convert actions tree to query - default implementation."""
|
68
|
-
script_strategy = self.to_native()
|
69
|
-
script_strategy._actions_tree = actions_tree
|
70
|
-
return script_strategy.to_format(self.get_query_type())
|
71
|
-
|
72
|
-
def get_query_type(self) -> str:
|
73
|
-
"""Get the query type for this strategy."""
|
74
|
-
return self.__class__.__name__.replace('Strategy', '').upper()
|
75
|
-
|
76
|
-
|
77
|
-
class AQueryActionExecutor(AQueryStrategy):
|
78
|
-
"""Abstract base for query action executors with XWQuery Script support."""
|
79
|
-
|
80
|
-
@abstractmethod
|
81
|
-
def execute_query(self, query: str, query_type: str, **kwargs) -> Any:
|
82
|
-
"""Execute a query on this backend."""
|
83
|
-
pass
|
84
|
-
|
85
|
-
@abstractmethod
|
86
|
-
def validate_query(self, query: str, query_type: str) -> bool:
|
87
|
-
"""Validate if this backend can handle the query."""
|
88
|
-
pass
|
89
|
-
|
90
|
-
@abstractmethod
|
91
|
-
def get_supported_query_types(self) -> List[str]:
|
92
|
-
"""Get list of query types this backend supports."""
|
93
|
-
pass
|
94
|
-
|
95
|
-
def to_native(self) -> 'XWQueryScriptStrategy':
|
96
|
-
"""Convert this executor to XWQueryScriptStrategy using actions."""
|
97
|
-
from .xwquery_strategy import XWQueryScriptStrategy
|
98
|
-
return XWQueryScriptStrategy()
|
99
|
-
|
100
|
-
def to_actions_tree(self, query: str) -> XWNodeBase:
|
101
|
-
"""Convert query to actions tree - default implementation."""
|
102
|
-
script_strategy = self.to_native().from_format(query, self.get_query_type())
|
103
|
-
return script_strategy.get_actions_tree()
|
104
|
-
|
105
|
-
def from_actions_tree(self, actions_tree: XWNodeBase) -> str:
|
106
|
-
"""Convert actions tree to query - default implementation."""
|
107
|
-
script_strategy = self.to_native()
|
108
|
-
script_strategy._actions_tree = actions_tree
|
109
|
-
return script_strategy.to_format(self.get_query_type())
|
110
|
-
|
111
|
-
|
112
|
-
class ALinearQueryStrategy(AQueryStrategy):
|
113
|
-
"""Linear query capabilities."""
|
114
|
-
|
115
|
-
def find_by_index(self, index: int) -> Any:
|
116
|
-
"""Find element by index."""
|
117
|
-
raise NotImplementedError("Subclasses must implement find_by_index")
|
118
|
-
|
119
|
-
def find_by_value(self, value: Any) -> List[int]:
|
120
|
-
"""Find indices by value."""
|
121
|
-
raise NotImplementedError("Subclasses must implement find_by_value")
|
122
|
-
|
123
|
-
def range_query(self, start_index: int, end_index: int) -> List[Any]:
|
124
|
-
"""Query range of indices."""
|
125
|
-
raise NotImplementedError("Subclasses must implement range_query")
|
126
|
-
|
127
|
-
def count_occurrences(self, value: Any) -> int:
|
128
|
-
"""Count occurrences of value."""
|
129
|
-
raise NotImplementedError("Subclasses must implement count_occurrences")
|
130
|
-
|
131
|
-
|
132
|
-
class ATreeQueryStrategy(AQueryStrategy):
|
133
|
-
"""Tree query capabilities."""
|
134
|
-
|
135
|
-
def find_by_key(self, key: Any) -> Any:
|
136
|
-
"""Find by key."""
|
137
|
-
raise NotImplementedError("Subclasses must implement find_by_key")
|
138
|
-
|
139
|
-
def range_query(self, start_key: Any, end_key: Any) -> List[Any]:
|
140
|
-
"""Range query."""
|
141
|
-
raise NotImplementedError("Subclasses must implement range_query")
|
142
|
-
|
143
|
-
def prefix_query(self, prefix: str) -> List[Any]:
|
144
|
-
"""Find all keys with prefix."""
|
145
|
-
raise NotImplementedError("Subclasses must implement prefix_query")
|
146
|
-
|
147
|
-
def suffix_query(self, suffix: str) -> List[Any]:
|
148
|
-
"""Find all keys with suffix."""
|
149
|
-
raise NotImplementedError("Subclasses must implement suffix_query")
|
150
|
-
|
151
|
-
|
152
|
-
class AGraphQueryStrategy(AQueryStrategy):
|
153
|
-
"""Graph query capabilities."""
|
154
|
-
|
155
|
-
def path_query(self, start: Any, end: Any) -> List[Any]:
|
156
|
-
"""Path query."""
|
157
|
-
raise NotImplementedError("Subclasses must implement path_query")
|
158
|
-
|
159
|
-
def neighbor_query(self, node: Any) -> List[Any]:
|
160
|
-
"""Neighbor query."""
|
161
|
-
raise NotImplementedError("Subclasses must implement neighbor_query")
|
162
|
-
|
163
|
-
def shortest_path_query(self, start: Any, end: Any) -> List[Any]:
|
164
|
-
"""Shortest path query."""
|
165
|
-
raise NotImplementedError("Subclasses must implement shortest_path_query")
|
166
|
-
|
167
|
-
def connected_components_query(self) -> List[List[Any]]:
|
168
|
-
"""Connected components query."""
|
169
|
-
raise NotImplementedError("Subclasses must implement connected_components_query")
|
170
|
-
|
171
|
-
def cycle_detection_query(self) -> List[List[Any]]:
|
172
|
-
"""Cycle detection query."""
|
173
|
-
raise NotImplementedError("Subclasses must implement cycle_detection_query")
|
174
|
-
|
175
|
-
|
176
|
-
class AStructuredQueryStrategy(AQueryStrategy):
|
177
|
-
"""Structured query capabilities for SQL-like languages."""
|
178
|
-
|
179
|
-
@abstractmethod
|
180
|
-
def select_query(self, table: str, columns: List[str], where_clause: str = None) -> Any:
|
181
|
-
"""Execute SELECT query."""
|
182
|
-
pass
|
183
|
-
|
184
|
-
@abstractmethod
|
185
|
-
def insert_query(self, table: str, data: Dict[str, Any]) -> Any:
|
186
|
-
"""Execute INSERT query."""
|
187
|
-
pass
|
188
|
-
|
189
|
-
@abstractmethod
|
190
|
-
def update_query(self, table: str, data: Dict[str, Any], where_clause: str = None) -> Any:
|
191
|
-
"""Execute UPDATE query."""
|
192
|
-
pass
|
193
|
-
|
194
|
-
@abstractmethod
|
195
|
-
def delete_query(self, table: str, where_clause: str = None) -> Any:
|
196
|
-
"""Execute DELETE query."""
|
197
|
-
pass
|
198
|
-
|
199
|
-
@abstractmethod
|
200
|
-
def join_query(self, tables: List[str], join_conditions: List[str]) -> Any:
|
201
|
-
"""Execute JOIN query."""
|
202
|
-
pass
|
203
|
-
|
204
|
-
@abstractmethod
|
205
|
-
def aggregate_query(self, table: str, functions: List[str], group_by: List[str] = None) -> Any:
|
206
|
-
"""Execute aggregate query."""
|
207
|
-
pass
|
208
|
-
|
209
|
-
|
210
|
-
class ADocumentQueryStrategy(AQueryStrategy):
|
211
|
-
"""Document query capabilities for JSON/XML-like languages."""
|
212
|
-
|
213
|
-
@abstractmethod
|
214
|
-
def path_query(self, path: str) -> Any:
|
215
|
-
"""Execute path-based query."""
|
216
|
-
pass
|
217
|
-
|
218
|
-
@abstractmethod
|
219
|
-
def filter_query(self, filter_expression: str) -> Any:
|
220
|
-
"""Execute filter query."""
|
221
|
-
pass
|
222
|
-
|
223
|
-
@abstractmethod
|
224
|
-
def projection_query(self, fields: List[str]) -> Any:
|
225
|
-
"""Execute projection query."""
|
226
|
-
pass
|
227
|
-
|
228
|
-
@abstractmethod
|
229
|
-
def sort_query(self, sort_fields: List[str], order: str = "asc") -> Any:
|
230
|
-
"""Execute sort query."""
|
231
|
-
pass
|
232
|
-
|
233
|
-
@abstractmethod
|
234
|
-
def limit_query(self, limit: int, offset: int = 0) -> Any:
|
235
|
-
"""Execute limit query."""
|
236
|
-
pass
|