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,70 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Elasticsearch DSL Query Strategy
|
4
|
+
|
5
|
+
This module implements the Elasticsearch DSL query strategy for Elasticsearch Query DSL operations.
|
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
|
+
from typing import Any, Dict, List, Optional
|
15
|
+
from .base import AStructuredQueryStrategy
|
16
|
+
from ...errors import XWNodeValueError
|
17
|
+
from ...contracts import QueryMode, QueryTrait
|
18
|
+
|
19
|
+
|
20
|
+
class ElasticDSLStrategy(AStructuredQueryStrategy):
|
21
|
+
"""Elasticsearch DSL query strategy for Elasticsearch Query DSL operations."""
|
22
|
+
|
23
|
+
def __init__(self, **options):
|
24
|
+
super().__init__(**options)
|
25
|
+
self._mode = QueryMode.ELASTIC_DSL
|
26
|
+
self._traits = QueryTrait.STRUCTURED | QueryTrait.ANALYTICAL | QueryTrait.SEARCH
|
27
|
+
|
28
|
+
def execute(self, query: str, **kwargs) -> Any:
|
29
|
+
"""Execute Elasticsearch DSL query."""
|
30
|
+
if not self.validate_query(query):
|
31
|
+
raise XWNodeValueError(f"Invalid Elasticsearch DSL query: {query}")
|
32
|
+
return {"result": "Elasticsearch DSL query executed", "query": query}
|
33
|
+
|
34
|
+
def validate_query(self, query: str) -> bool:
|
35
|
+
"""Validate Elasticsearch DSL query syntax."""
|
36
|
+
if not query or not isinstance(query, str):
|
37
|
+
return False
|
38
|
+
return any(op in query for op in ["query", "match", "term", "bool", "filter", "must", "should"])
|
39
|
+
|
40
|
+
def get_query_plan(self, query: str) -> Dict[str, Any]:
|
41
|
+
"""Get Elasticsearch DSL query execution plan."""
|
42
|
+
return {
|
43
|
+
"query_type": "ELASTIC_DSL",
|
44
|
+
"complexity": "HIGH",
|
45
|
+
"estimated_cost": 120
|
46
|
+
}
|
47
|
+
|
48
|
+
def select_query(self, table: str, columns: List[str], where_clause: str = None) -> Any:
|
49
|
+
"""Execute SELECT query."""
|
50
|
+
return self.execute(f"GET /{table}/_search")
|
51
|
+
|
52
|
+
def insert_query(self, table: str, data: Dict[str, Any]) -> Any:
|
53
|
+
"""Execute INSERT query."""
|
54
|
+
return self.execute(f"POST /{table}/_doc")
|
55
|
+
|
56
|
+
def update_query(self, table: str, data: Dict[str, Any], where_clause: str = None) -> Any:
|
57
|
+
"""Execute UPDATE query."""
|
58
|
+
return self.execute(f"POST /{table}/_update_by_query")
|
59
|
+
|
60
|
+
def delete_query(self, table: str, where_clause: str = None) -> Any:
|
61
|
+
"""Execute DELETE query."""
|
62
|
+
return self.execute(f"POST /{table}/_delete_by_query")
|
63
|
+
|
64
|
+
def join_query(self, tables: List[str], join_conditions: List[str]) -> Any:
|
65
|
+
"""Execute JOIN query."""
|
66
|
+
return self.execute(f"GET /{tables[0]}/_search")
|
67
|
+
|
68
|
+
def aggregate_query(self, table: str, functions: List[str], group_by: List[str] = None) -> Any:
|
69
|
+
"""Execute aggregate query."""
|
70
|
+
return self.execute(f"GET /{table}/_search")
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
EQL Query Strategy
|
4
|
+
|
5
|
+
This module implements the EQL query strategy for Elasticsearch Query Language operations.
|
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
|
+
from typing import Any, Dict, List, Optional
|
15
|
+
from .base import AStructuredQueryStrategy
|
16
|
+
from ...errors import XWNodeValueError
|
17
|
+
from ...contracts import QueryMode, QueryTrait
|
18
|
+
|
19
|
+
|
20
|
+
class EQLStrategy(AStructuredQueryStrategy):
|
21
|
+
"""EQL query strategy for Elasticsearch Query Language operations."""
|
22
|
+
|
23
|
+
def __init__(self, **options):
|
24
|
+
super().__init__(**options)
|
25
|
+
self._mode = QueryMode.EQL
|
26
|
+
self._traits = QueryTrait.STRUCTURED | QueryTrait.ANALYTICAL | QueryTrait.BATCH
|
27
|
+
|
28
|
+
def execute(self, query: str, **kwargs) -> Any:
|
29
|
+
"""Execute EQL query."""
|
30
|
+
if not self.validate_query(query):
|
31
|
+
raise XWNodeValueError(f"Invalid EQL query: {query}")
|
32
|
+
return {"result": "EQL query executed", "query": query}
|
33
|
+
|
34
|
+
def validate_query(self, query: str) -> bool:
|
35
|
+
"""Validate EQL query syntax."""
|
36
|
+
if not query or not isinstance(query, str):
|
37
|
+
return False
|
38
|
+
return any(op in query.upper() for op in ["SEQUENCE", "JOIN", "FILTER", "WHERE"])
|
39
|
+
|
40
|
+
def get_query_plan(self, query: str) -> Dict[str, Any]:
|
41
|
+
"""Get EQL query execution plan."""
|
42
|
+
return {
|
43
|
+
"query_type": "EQL",
|
44
|
+
"complexity": "MEDIUM",
|
45
|
+
"estimated_cost": 100
|
46
|
+
}
|
47
|
+
|
48
|
+
def select_query(self, table: str, columns: List[str], where_clause: str = None) -> Any:
|
49
|
+
"""Execute SELECT query."""
|
50
|
+
return self.execute(f"SELECT {', '.join(columns)} FROM {table}")
|
51
|
+
|
52
|
+
def insert_query(self, table: str, data: Dict[str, Any]) -> Any:
|
53
|
+
"""Execute INSERT query."""
|
54
|
+
return self.execute(f"INSERT INTO {table} VALUES {data}")
|
55
|
+
|
56
|
+
def update_query(self, table: str, data: Dict[str, Any], where_clause: str = None) -> Any:
|
57
|
+
"""Execute UPDATE query."""
|
58
|
+
return self.execute(f"UPDATE {table} SET {data}")
|
59
|
+
|
60
|
+
def delete_query(self, table: str, where_clause: str = None) -> Any:
|
61
|
+
"""Execute DELETE query."""
|
62
|
+
return self.execute(f"DELETE FROM {table}")
|
63
|
+
|
64
|
+
def join_query(self, tables: List[str], join_conditions: List[str]) -> Any:
|
65
|
+
"""Execute JOIN query."""
|
66
|
+
return self.execute(f"JOIN {tables[0]} WITH {tables[1]}")
|
67
|
+
|
68
|
+
def aggregate_query(self, table: str, functions: List[str], group_by: List[str] = None) -> Any:
|
69
|
+
"""Execute aggregate query."""
|
70
|
+
return self.execute(f"AGGREGATE {', '.join(functions)} FROM {table}")
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Flux Query Strategy
|
4
|
+
|
5
|
+
This module implements the Flux query strategy for InfluxDB Flux operations.
|
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
|
+
from typing import Any, Dict, List, Optional
|
15
|
+
from .base import AStructuredQueryStrategy
|
16
|
+
from ...errors import XWNodeValueError
|
17
|
+
from ...contracts import QueryMode, QueryTrait
|
18
|
+
|
19
|
+
|
20
|
+
class FluxStrategy(AStructuredQueryStrategy):
|
21
|
+
"""Flux query strategy for InfluxDB Flux operations."""
|
22
|
+
|
23
|
+
def __init__(self, **options):
|
24
|
+
super().__init__(**options)
|
25
|
+
self._mode = QueryMode.FLUX
|
26
|
+
self._traits = QueryTrait.STRUCTURED | QueryTrait.ANALYTICAL | QueryTrait.BATCH
|
27
|
+
|
28
|
+
def execute(self, query: str, **kwargs) -> Any:
|
29
|
+
"""Execute Flux query."""
|
30
|
+
if not self.validate_query(query):
|
31
|
+
raise XWNodeValueError(f"Invalid Flux query: {query}")
|
32
|
+
return {"result": "Flux query executed", "query": query}
|
33
|
+
|
34
|
+
def validate_query(self, query: str) -> bool:
|
35
|
+
"""Validate Flux query syntax."""
|
36
|
+
if not query or not isinstance(query, str):
|
37
|
+
return False
|
38
|
+
return any(op in query for op in ["from", "range", "filter", "aggregate", "yield"])
|
39
|
+
|
40
|
+
def get_query_plan(self, query: str) -> Dict[str, Any]:
|
41
|
+
"""Get Flux query execution plan."""
|
42
|
+
return {
|
43
|
+
"query_type": "Flux",
|
44
|
+
"complexity": "MEDIUM",
|
45
|
+
"estimated_cost": 110
|
46
|
+
}
|
47
|
+
|
48
|
+
def select_query(self, table: str, columns: List[str], where_clause: str = None) -> Any:
|
49
|
+
"""Execute SELECT query."""
|
50
|
+
return self.execute(f"from(bucket: \"{table}\") | filter(fn: (r) => r._field =~ /{columns[0]}/)")
|
51
|
+
|
52
|
+
def insert_query(self, table: str, data: Dict[str, Any]) -> Any:
|
53
|
+
"""Execute INSERT query."""
|
54
|
+
return self.execute(f"INSERT INTO {table} VALUES {data}")
|
55
|
+
|
56
|
+
def update_query(self, table: str, data: Dict[str, Any], where_clause: str = None) -> Any:
|
57
|
+
"""Execute UPDATE query."""
|
58
|
+
return self.execute(f"UPDATE {table} SET {data}")
|
59
|
+
|
60
|
+
def delete_query(self, table: str, where_clause: str = None) -> Any:
|
61
|
+
"""Execute DELETE query."""
|
62
|
+
return self.execute(f"DELETE FROM {table}")
|
63
|
+
|
64
|
+
def join_query(self, tables: List[str], join_conditions: List[str]) -> Any:
|
65
|
+
"""Execute JOIN query."""
|
66
|
+
return self.execute(f"join(tables: {{t1: {tables[0]}, t2: {tables[1]}}})")
|
67
|
+
|
68
|
+
def aggregate_query(self, table: str, functions: List[str], group_by: List[str] = None) -> Any:
|
69
|
+
"""Execute aggregate query."""
|
70
|
+
return self.execute(f"from(bucket: \"{table}\") | aggregateWindow(every: 1m, fn: {functions[0]})")
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
GQL Query Strategy
|
4
|
+
|
5
|
+
This module implements the GQL query strategy for ISO/IEC 39075:2024 Graph Query Language operations.
|
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
|
+
from typing import Any, Dict, List, Optional
|
15
|
+
from .base import AGraphQueryStrategy
|
16
|
+
from ...errors import XWNodeValueError
|
17
|
+
from ...contracts import QueryMode, QueryTrait
|
18
|
+
|
19
|
+
|
20
|
+
class GQLStrategy(AGraphQueryStrategy):
|
21
|
+
"""GQL query strategy for ISO/IEC 39075:2024 Graph Query Language operations."""
|
22
|
+
|
23
|
+
def __init__(self, **options):
|
24
|
+
super().__init__(**options)
|
25
|
+
self._mode = QueryMode.GQL
|
26
|
+
self._traits = QueryTrait.GRAPH | QueryTrait.STRUCTURED | QueryTrait.ANALYTICAL
|
27
|
+
|
28
|
+
def execute(self, query: str, **kwargs) -> Any:
|
29
|
+
"""Execute GQL query."""
|
30
|
+
if not self.validate_query(query):
|
31
|
+
raise XWNodeValueError(f"Invalid GQL query: {query}")
|
32
|
+
return {"result": "GQL query executed", "query": query}
|
33
|
+
|
34
|
+
def validate_query(self, query: str) -> bool:
|
35
|
+
"""Validate GQL query syntax."""
|
36
|
+
if not query or not isinstance(query, str):
|
37
|
+
return False
|
38
|
+
return any(op in query.upper() for op in ["MATCH", "SELECT", "WHERE", "RETURN", "CREATE", "DELETE"])
|
39
|
+
|
40
|
+
def get_query_plan(self, query: str) -> Dict[str, Any]:
|
41
|
+
"""Get GQL query execution plan."""
|
42
|
+
return {
|
43
|
+
"query_type": "GQL",
|
44
|
+
"complexity": "HIGH",
|
45
|
+
"estimated_cost": 150
|
46
|
+
}
|
47
|
+
|
48
|
+
def match_query(self, pattern: str, where_clause: str = None) -> Any:
|
49
|
+
"""Execute MATCH query."""
|
50
|
+
return self.execute(f"MATCH {pattern}")
|
51
|
+
|
52
|
+
def create_query(self, pattern: str) -> Any:
|
53
|
+
"""Execute CREATE query."""
|
54
|
+
return self.execute(f"CREATE {pattern}")
|
55
|
+
|
56
|
+
def delete_query(self, pattern: str) -> Any:
|
57
|
+
"""Execute DELETE query."""
|
58
|
+
return self.execute(f"DELETE {pattern}")
|
59
|
+
|
60
|
+
def set_query(self, pattern: str) -> Any:
|
61
|
+
"""Execute SET query."""
|
62
|
+
return self.execute(f"SET {pattern}")
|
63
|
+
|
64
|
+
def remove_query(self, pattern: str) -> Any:
|
65
|
+
"""Execute REMOVE query."""
|
66
|
+
return self.execute(f"REMOVE {pattern}")
|
67
|
+
|
68
|
+
def merge_query(self, pattern: str) -> Any:
|
69
|
+
"""Execute MERGE query."""
|
70
|
+
return self.execute(f"MERGE {pattern}")
|
@@ -0,0 +1,240 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
GraphQL Query Strategy
|
4
|
+
|
5
|
+
This module implements the GraphQL query strategy for graph-based 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 AGraphQueryStrategy
|
17
|
+
from ...errors import XWNodeTypeError, XWNodeValueError
|
18
|
+
from ...contracts import QueryMode, QueryTrait
|
19
|
+
|
20
|
+
|
21
|
+
class GraphQLStrategy(AGraphQueryStrategy):
|
22
|
+
"""
|
23
|
+
GraphQL query strategy for graph-based data queries.
|
24
|
+
|
25
|
+
Supports:
|
26
|
+
- Queries and mutations
|
27
|
+
- Fragments and variables
|
28
|
+
- Introspection
|
29
|
+
- Subscriptions
|
30
|
+
- Schema validation
|
31
|
+
"""
|
32
|
+
|
33
|
+
def __init__(self, **options):
|
34
|
+
super().__init__(**options)
|
35
|
+
self._mode = QueryMode.GRAPHQL
|
36
|
+
self._traits = QueryTrait.GRAPH | QueryTrait.STRUCTURED | QueryTrait.ANALYTICAL
|
37
|
+
|
38
|
+
def execute(self, query: str, **kwargs) -> Any:
|
39
|
+
"""Execute GraphQL query."""
|
40
|
+
if not self.validate_query(query):
|
41
|
+
raise XWNodeValueError(f"Invalid GraphQL query: {query}")
|
42
|
+
|
43
|
+
query_type = self._get_query_type(query)
|
44
|
+
|
45
|
+
if query_type == "query":
|
46
|
+
return self._execute_query(query, **kwargs)
|
47
|
+
elif query_type == "mutation":
|
48
|
+
return self._execute_mutation(query, **kwargs)
|
49
|
+
elif query_type == "subscription":
|
50
|
+
return self._execute_subscription(query, **kwargs)
|
51
|
+
else:
|
52
|
+
raise XWNodeValueError(f"Unsupported query type: {query_type}")
|
53
|
+
|
54
|
+
def validate_query(self, query: str) -> bool:
|
55
|
+
"""Validate GraphQL query syntax."""
|
56
|
+
if not query or not isinstance(query, str):
|
57
|
+
return False
|
58
|
+
|
59
|
+
# Basic GraphQL validation
|
60
|
+
query = query.strip()
|
61
|
+
|
62
|
+
# Check for valid GraphQL operations
|
63
|
+
valid_operations = ["query", "mutation", "subscription"]
|
64
|
+
for operation in valid_operations:
|
65
|
+
if query.startswith(operation) or query.startswith("{"):
|
66
|
+
return True
|
67
|
+
|
68
|
+
return False
|
69
|
+
|
70
|
+
def get_query_plan(self, query: str) -> Dict[str, Any]:
|
71
|
+
"""Get GraphQL query execution plan."""
|
72
|
+
query_type = self._get_query_type(query)
|
73
|
+
|
74
|
+
return {
|
75
|
+
"query_type": query_type,
|
76
|
+
"operation": query_type,
|
77
|
+
"complexity": self._estimate_complexity(query),
|
78
|
+
"estimated_cost": self._estimate_cost(query),
|
79
|
+
"fields": self._extract_fields(query),
|
80
|
+
"optimization_hints": self._get_optimization_hints(query)
|
81
|
+
}
|
82
|
+
|
83
|
+
def path_query(self, start: Any, end: Any) -> List[Any]:
|
84
|
+
"""Execute path query."""
|
85
|
+
query = f"""
|
86
|
+
query {{
|
87
|
+
path(start: "{start}", end: "{end}") {{
|
88
|
+
nodes
|
89
|
+
edges
|
90
|
+
cost
|
91
|
+
}}
|
92
|
+
}}
|
93
|
+
"""
|
94
|
+
return self.execute(query)
|
95
|
+
|
96
|
+
def neighbor_query(self, node: Any) -> List[Any]:
|
97
|
+
"""Execute neighbor query."""
|
98
|
+
query = f"""
|
99
|
+
query {{
|
100
|
+
node(id: "{node}") {{
|
101
|
+
neighbors {{
|
102
|
+
id
|
103
|
+
properties
|
104
|
+
}}
|
105
|
+
}}
|
106
|
+
}}
|
107
|
+
"""
|
108
|
+
return self.execute(query)
|
109
|
+
|
110
|
+
def shortest_path_query(self, start: Any, end: Any) -> List[Any]:
|
111
|
+
"""Execute shortest path query."""
|
112
|
+
query = f"""
|
113
|
+
query {{
|
114
|
+
shortestPath(start: "{start}", end: "{end}") {{
|
115
|
+
path
|
116
|
+
distance
|
117
|
+
hops
|
118
|
+
}}
|
119
|
+
}}
|
120
|
+
"""
|
121
|
+
return self.execute(query)
|
122
|
+
|
123
|
+
def connected_components_query(self) -> List[List[Any]]:
|
124
|
+
"""Execute connected components query."""
|
125
|
+
query = """
|
126
|
+
query {
|
127
|
+
connectedComponents {
|
128
|
+
components {
|
129
|
+
nodes
|
130
|
+
size
|
131
|
+
}
|
132
|
+
}
|
133
|
+
}
|
134
|
+
"""
|
135
|
+
return self.execute(query)
|
136
|
+
|
137
|
+
def cycle_detection_query(self) -> List[List[Any]]:
|
138
|
+
"""Execute cycle detection query."""
|
139
|
+
query = """
|
140
|
+
query {
|
141
|
+
cycles {
|
142
|
+
cycles {
|
143
|
+
nodes
|
144
|
+
length
|
145
|
+
}
|
146
|
+
}
|
147
|
+
}
|
148
|
+
"""
|
149
|
+
return self.execute(query)
|
150
|
+
|
151
|
+
def _get_query_type(self, query: str) -> str:
|
152
|
+
"""Extract query type from GraphQL query."""
|
153
|
+
query = query.strip()
|
154
|
+
|
155
|
+
if query.startswith("mutation"):
|
156
|
+
return "mutation"
|
157
|
+
elif query.startswith("subscription"):
|
158
|
+
return "subscription"
|
159
|
+
elif query.startswith("query") or query.startswith("{"):
|
160
|
+
return "query"
|
161
|
+
else:
|
162
|
+
return "unknown"
|
163
|
+
|
164
|
+
def _execute_query(self, query: str, **kwargs) -> Any:
|
165
|
+
"""Execute GraphQL query."""
|
166
|
+
return {"result": "GraphQL query executed", "query": query}
|
167
|
+
|
168
|
+
def _execute_mutation(self, query: str, **kwargs) -> Any:
|
169
|
+
"""Execute GraphQL mutation."""
|
170
|
+
return {"result": "GraphQL mutation executed", "query": query}
|
171
|
+
|
172
|
+
def _execute_subscription(self, query: str, **kwargs) -> Any:
|
173
|
+
"""Execute GraphQL subscription."""
|
174
|
+
return {"result": "GraphQL subscription executed", "query": query}
|
175
|
+
|
176
|
+
def _estimate_complexity(self, query: str) -> str:
|
177
|
+
"""Estimate query complexity."""
|
178
|
+
# Count nested fields and connections
|
179
|
+
depth = self._calculate_query_depth(query)
|
180
|
+
|
181
|
+
if depth > 5:
|
182
|
+
return "HIGH"
|
183
|
+
elif depth > 2:
|
184
|
+
return "MEDIUM"
|
185
|
+
else:
|
186
|
+
return "LOW"
|
187
|
+
|
188
|
+
def _estimate_cost(self, query: str) -> int:
|
189
|
+
"""Estimate query cost."""
|
190
|
+
complexity = self._estimate_complexity(query)
|
191
|
+
if complexity == "HIGH":
|
192
|
+
return 150
|
193
|
+
elif complexity == "MEDIUM":
|
194
|
+
return 75
|
195
|
+
else:
|
196
|
+
return 25
|
197
|
+
|
198
|
+
def _calculate_query_depth(self, query: str) -> int:
|
199
|
+
"""Calculate query nesting depth."""
|
200
|
+
depth = 0
|
201
|
+
max_depth = 0
|
202
|
+
|
203
|
+
for char in query:
|
204
|
+
if char == '{':
|
205
|
+
depth += 1
|
206
|
+
max_depth = max(max_depth, depth)
|
207
|
+
elif char == '}':
|
208
|
+
depth -= 1
|
209
|
+
|
210
|
+
return max_depth
|
211
|
+
|
212
|
+
def _extract_fields(self, query: str) -> List[str]:
|
213
|
+
"""Extract field names from GraphQL query."""
|
214
|
+
# Simple field extraction
|
215
|
+
fields = []
|
216
|
+
lines = query.split('\n')
|
217
|
+
|
218
|
+
for line in lines:
|
219
|
+
line = line.strip()
|
220
|
+
if line and not line.startswith('{') and not line.startswith('}'):
|
221
|
+
if ':' in line:
|
222
|
+
field = line.split(':')[0].strip()
|
223
|
+
fields.append(field)
|
224
|
+
|
225
|
+
return fields
|
226
|
+
|
227
|
+
def _get_optimization_hints(self, query: str) -> List[str]:
|
228
|
+
"""Get query optimization hints."""
|
229
|
+
hints = []
|
230
|
+
|
231
|
+
if self._calculate_query_depth(query) > 3:
|
232
|
+
hints.append("Consider reducing query depth to improve performance")
|
233
|
+
|
234
|
+
if "..." in query:
|
235
|
+
hints.append("Consider using fragments for reusable query parts")
|
236
|
+
|
237
|
+
if query.count('{') > 10:
|
238
|
+
hints.append("Consider breaking down complex queries into smaller ones")
|
239
|
+
|
240
|
+
return hints
|