exonware-xwnode 0.0.1.13__py3-none-any.whl → 0.0.1.15__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 +1 -1
- exonware/xwnode/__init__.py +1 -1
- exonware/xwnode/base.py +1 -1
- exonware/xwnode/common/__init__.py +20 -0
- exonware/xwnode/common/management/__init__.py +26 -0
- exonware/xwnode/{strategies → common/management}/manager.py +2 -2
- exonware/xwnode/common/monitoring/__init__.py +26 -0
- exonware/xwnode/{strategies → common/monitoring}/metrics.py +2 -2
- exonware/xwnode/{strategies → common/monitoring}/pattern_detector.py +2 -2
- exonware/xwnode/{strategies → common/monitoring}/performance_monitor.py +2 -2
- exonware/xwnode/common/patterns/__init__.py +26 -0
- exonware/xwnode/{strategies → common/patterns}/advisor.py +1 -1
- exonware/xwnode/{strategies → common/patterns}/flyweight.py +4 -4
- exonware/xwnode/{strategies → common/patterns}/registry.py +109 -112
- exonware/xwnode/common/utils/__init__.py +26 -0
- exonware/xwnode/{strategies/edges → edges/strategies}/__init__.py +1 -1
- exonware/xwnode/{strategies/edges → edges/strategies}/base.py +3 -3
- exonware/xwnode/facade.py +4 -3
- exonware/xwnode/{strategies/nodes → nodes/strategies}/__init__.py +1 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/adjacency_list.py +7 -2
- exonware/xwnode/{strategies/nodes → nodes/strategies}/aho_corasick.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/array_list.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/base.py +24 -4
- exonware/xwnode/nodes/strategies/contracts.py +116 -0
- exonware/xwnode/{strategies/nodes → nodes/strategies}/deque.py +7 -2
- exonware/xwnode/{strategies/nodes → nodes/strategies}/hash_map.py +4 -0
- exonware/xwnode/{strategies/nodes → nodes/strategies}/heap.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/linked_list.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_aho_corasick.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_array_list.py +4 -0
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_avl_tree.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_b_plus_tree.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_bitmap.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_bitset_dynamic.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_bloom_filter.py +4 -0
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_btree.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_count_min_sketch.py +4 -0
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_cow_tree.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_fenwick_tree.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_hash_map.py +4 -0
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_heap.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_hyperloglog.py +4 -0
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_linked_list.py +4 -0
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_lsm_tree.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_ordered_map.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_ordered_map_balanced.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_patricia.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_persistent_tree.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_radix_trie.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_red_black_tree.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_roaring_bitmap.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_segment_tree.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_set_hash.py +4 -0
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_set_tree.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_skip_list.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_splay_tree.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_suffix_array.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_treap.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_tree_graph_hybrid.py +4 -0
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_trie.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_union_find.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/node_xdata_optimized.py +4 -0
- exonware/xwnode/{strategies/nodes → nodes/strategies}/priority_queue.py +7 -2
- exonware/xwnode/{strategies/nodes → nodes/strategies}/queue.py +7 -2
- exonware/xwnode/{strategies/nodes → nodes/strategies}/sparse_matrix.py +7 -2
- exonware/xwnode/{strategies/nodes → nodes/strategies}/stack.py +7 -2
- exonware/xwnode/{strategies/nodes → nodes/strategies}/trie.py +6 -1
- exonware/xwnode/{strategies/nodes → nodes/strategies}/union_find.py +6 -1
- exonware/xwnode/queries/executors/__init__.py +47 -0
- exonware/xwnode/queries/executors/advanced/__init__.py +37 -0
- exonware/xwnode/queries/executors/advanced/aggregate_executor.py +50 -0
- exonware/xwnode/queries/executors/advanced/ask_executor.py +50 -0
- exonware/xwnode/queries/executors/advanced/construct_executor.py +50 -0
- exonware/xwnode/queries/executors/advanced/describe_executor.py +50 -0
- exonware/xwnode/queries/executors/advanced/for_loop_executor.py +50 -0
- exonware/xwnode/queries/executors/advanced/foreach_executor.py +50 -0
- exonware/xwnode/queries/executors/advanced/join_executor.py +50 -0
- exonware/xwnode/queries/executors/advanced/let_executor.py +50 -0
- exonware/xwnode/queries/executors/advanced/mutation_executor.py +50 -0
- exonware/xwnode/queries/executors/advanced/options_executor.py +50 -0
- exonware/xwnode/queries/executors/advanced/pipe_executor.py +50 -0
- exonware/xwnode/queries/executors/advanced/subscribe_executor.py +50 -0
- exonware/xwnode/queries/executors/advanced/subscription_executor.py +50 -0
- exonware/xwnode/queries/executors/advanced/union_executor.py +50 -0
- exonware/xwnode/queries/executors/advanced/window_executor.py +51 -0
- exonware/xwnode/queries/executors/advanced/with_cte_executor.py +50 -0
- exonware/xwnode/queries/executors/aggregation/__init__.py +21 -0
- exonware/xwnode/queries/executors/aggregation/avg_executor.py +50 -0
- exonware/xwnode/queries/executors/aggregation/count_executor.py +38 -0
- exonware/xwnode/queries/executors/aggregation/distinct_executor.py +50 -0
- exonware/xwnode/queries/executors/aggregation/group_executor.py +50 -0
- exonware/xwnode/queries/executors/aggregation/having_executor.py +50 -0
- exonware/xwnode/queries/executors/aggregation/max_executor.py +50 -0
- exonware/xwnode/queries/executors/aggregation/min_executor.py +50 -0
- exonware/xwnode/queries/executors/aggregation/sum_executor.py +50 -0
- exonware/xwnode/queries/executors/aggregation/summarize_executor.py +50 -0
- exonware/xwnode/queries/executors/array/__init__.py +9 -0
- exonware/xwnode/queries/executors/array/indexing_executor.py +51 -0
- exonware/xwnode/queries/executors/array/slicing_executor.py +51 -0
- exonware/xwnode/queries/executors/base.py +257 -0
- exonware/xwnode/queries/executors/capability_checker.py +204 -0
- exonware/xwnode/queries/executors/contracts.py +166 -0
- exonware/xwnode/queries/executors/core/__init__.py +17 -0
- exonware/xwnode/queries/executors/core/create_executor.py +96 -0
- exonware/xwnode/queries/executors/core/delete_executor.py +99 -0
- exonware/xwnode/queries/executors/core/drop_executor.py +100 -0
- exonware/xwnode/queries/executors/core/insert_executor.py +39 -0
- exonware/xwnode/queries/executors/core/select_executor.py +152 -0
- exonware/xwnode/queries/executors/core/update_executor.py +102 -0
- exonware/xwnode/queries/executors/data/__init__.py +13 -0
- exonware/xwnode/queries/executors/data/alter_executor.py +50 -0
- exonware/xwnode/queries/executors/data/load_executor.py +50 -0
- exonware/xwnode/queries/executors/data/merge_executor.py +50 -0
- exonware/xwnode/queries/executors/data/store_executor.py +50 -0
- exonware/xwnode/queries/executors/engine.py +221 -0
- exonware/xwnode/queries/executors/errors.py +68 -0
- exonware/xwnode/queries/executors/filtering/__init__.py +25 -0
- exonware/xwnode/queries/executors/filtering/between_executor.py +80 -0
- exonware/xwnode/queries/executors/filtering/filter_executor.py +79 -0
- exonware/xwnode/queries/executors/filtering/has_executor.py +70 -0
- exonware/xwnode/queries/executors/filtering/in_executor.py +70 -0
- exonware/xwnode/queries/executors/filtering/like_executor.py +76 -0
- exonware/xwnode/queries/executors/filtering/optional_executor.py +76 -0
- exonware/xwnode/queries/executors/filtering/range_executor.py +80 -0
- exonware/xwnode/queries/executors/filtering/term_executor.py +77 -0
- exonware/xwnode/queries/executors/filtering/values_executor.py +71 -0
- exonware/xwnode/queries/executors/filtering/where_executor.py +44 -0
- exonware/xwnode/queries/executors/graph/__init__.py +15 -0
- exonware/xwnode/queries/executors/graph/in_traverse_executor.py +51 -0
- exonware/xwnode/queries/executors/graph/match_executor.py +51 -0
- exonware/xwnode/queries/executors/graph/out_executor.py +51 -0
- exonware/xwnode/queries/executors/graph/path_executor.py +51 -0
- exonware/xwnode/queries/executors/graph/return_executor.py +51 -0
- exonware/xwnode/queries/executors/ordering/__init__.py +9 -0
- exonware/xwnode/queries/executors/ordering/by_executor.py +50 -0
- exonware/xwnode/queries/executors/ordering/order_executor.py +51 -0
- exonware/xwnode/queries/executors/projection/__init__.py +9 -0
- exonware/xwnode/queries/executors/projection/extend_executor.py +50 -0
- exonware/xwnode/queries/executors/projection/project_executor.py +50 -0
- exonware/xwnode/queries/executors/registry.py +173 -0
- exonware/xwnode/queries/executors/types.py +93 -0
- exonware/xwnode/queries/parsers/__init__.py +26 -0
- exonware/xwnode/queries/parsers/base.py +86 -0
- exonware/xwnode/queries/parsers/contracts.py +46 -0
- exonware/xwnode/queries/parsers/errors.py +53 -0
- exonware/xwnode/queries/parsers/sql_param_extractor.py +318 -0
- exonware/xwnode/{strategies/queries → queries/strategies}/__init__.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/base.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/cql.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/cypher.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/datalog.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/elastic_dsl.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/eql.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/flux.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/gql.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/graphql.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/gremlin.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/hiveql.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/hql.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/jmespath.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/jq.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/json_query.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/jsoniq.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/kql.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/linq.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/logql.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/mql.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/n1ql.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/partiql.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/pig.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/promql.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/sparql.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/sql.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/xml_query.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/xpath.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/xquery.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/xwnode_executor.py +1 -1
- exonware/xwnode/{strategies/queries → queries/strategies}/xwquery.py +43 -11
- exonware/xwnode/strategies/__init__.py +8 -8
- exonware/xwnode/version.py +3 -3
- {exonware_xwnode-0.0.1.13.dist-info → exonware_xwnode-0.0.1.15.dist-info}/METADATA +2 -3
- exonware_xwnode-0.0.1.15.dist-info/RECORD +214 -0
- exonware/xwnode/strategies/impls/__init__.py +0 -13
- exonware/xwnode/strategies/nodes/_base_node.py +0 -307
- exonware_xwnode-0.0.1.13.dist-info/RECORD +0 -132
- /exonware/xwnode/{strategies → common/management}/migration.py +0 -0
- /exonware/xwnode/{strategies → common/utils}/simple.py +0 -0
- /exonware/xwnode/{strategies → common/utils}/utils.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/_base_edge.py +0 -0
- /exonware/xwnode/{strategies/edges → edges/strategies}/adj_list.py +0 -0
- /exonware/xwnode/{strategies/edges → edges/strategies}/adj_matrix.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_adj_list.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_adj_matrix.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_bidir_wrapper.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_block_adj_matrix.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_coo.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_csc.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_csr.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_dynamic_adj_list.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_flow_network.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_hyperedge_set.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_neural_graph.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_octree.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_property_store.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_quadtree.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_rtree.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_temporal_edgeset.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_tree_graph_basic.py +0 -0
- /exonware/xwnode/{strategies/impls → edges/strategies}/edge_weighted_graph.py +0 -0
- /exonware/xwnode/{strategies/impls → nodes/strategies}/_base_node.py +0 -0
- /exonware/xwnode/{strategies/nodes → nodes/strategies}/node_cuckoo_hash.py +0 -0
- {exonware_xwnode-0.0.1.13.dist-info → exonware_xwnode-0.0.1.15.dist-info}/WHEEL +0 -0
- {exonware_xwnode-0.0.1.13.dist-info → exonware_xwnode-0.0.1.15.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,257 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
#exonware/xwnode/src/exonware/xwnode/queries/executors/base.py
|
4
|
+
|
5
|
+
Operation Executor Base Classes
|
6
|
+
|
7
|
+
This module provides base classes for operation executors with capability checking.
|
8
|
+
|
9
|
+
Company: eXonware.com
|
10
|
+
Author: Eng. Muhammad AlShehri
|
11
|
+
Email: connect@exonware.com
|
12
|
+
Version: 0.0.1.15
|
13
|
+
Generation Date: 08-Oct-2025
|
14
|
+
"""
|
15
|
+
|
16
|
+
import time
|
17
|
+
from abc import ABC, abstractmethod
|
18
|
+
from typing import Any, Dict, List, Optional
|
19
|
+
|
20
|
+
from .contracts import (
|
21
|
+
IOperationExecutor,
|
22
|
+
Action,
|
23
|
+
ExecutionContext,
|
24
|
+
ExecutionResult,
|
25
|
+
NodeType
|
26
|
+
)
|
27
|
+
from .types import OperationCapability
|
28
|
+
from .errors import UnsupportedOperationError # Reuse from root via errors.py
|
29
|
+
from ...errors import XWNodeValueError
|
30
|
+
|
31
|
+
|
32
|
+
class AOperationExecutor(IOperationExecutor):
|
33
|
+
"""
|
34
|
+
Abstract base class for operation executors.
|
35
|
+
|
36
|
+
Provides common functionality including:
|
37
|
+
- Capability checking
|
38
|
+
- Performance monitoring
|
39
|
+
- Error handling
|
40
|
+
- Validation
|
41
|
+
"""
|
42
|
+
|
43
|
+
# Operation name (must be set by subclasses)
|
44
|
+
OPERATION_NAME: str = "UNKNOWN"
|
45
|
+
|
46
|
+
# Supported node types (empty = all types)
|
47
|
+
SUPPORTED_NODE_TYPES: List[NodeType] = []
|
48
|
+
|
49
|
+
# Required capabilities
|
50
|
+
REQUIRED_CAPABILITIES: OperationCapability = OperationCapability.NONE
|
51
|
+
|
52
|
+
def __init__(self):
|
53
|
+
"""Initialize operation executor."""
|
54
|
+
self._execution_count = 0
|
55
|
+
self._total_time = 0.0
|
56
|
+
self._error_count = 0
|
57
|
+
|
58
|
+
def execute(self, action: Action, context: ExecutionContext) -> ExecutionResult:
|
59
|
+
"""
|
60
|
+
Execute operation with monitoring and error handling.
|
61
|
+
|
62
|
+
This method implements the Template Method pattern:
|
63
|
+
1. Validate
|
64
|
+
2. Check capability
|
65
|
+
3. Execute (delegated to subclass)
|
66
|
+
4. Monitor performance
|
67
|
+
"""
|
68
|
+
start_time = time.time()
|
69
|
+
|
70
|
+
try:
|
71
|
+
# Validate action
|
72
|
+
if not self.validate(action, context):
|
73
|
+
raise XWNodeValueError(f"Invalid action: {action.type}")
|
74
|
+
|
75
|
+
# Check capability
|
76
|
+
self.validate_capability_or_raise(context)
|
77
|
+
|
78
|
+
# Execute (delegated to subclass)
|
79
|
+
result = self._do_execute(action, context)
|
80
|
+
|
81
|
+
# Update metrics
|
82
|
+
execution_time = time.time() - start_time
|
83
|
+
self._execution_count += 1
|
84
|
+
self._total_time += execution_time
|
85
|
+
result.execution_time = execution_time
|
86
|
+
|
87
|
+
return result
|
88
|
+
|
89
|
+
except Exception as e:
|
90
|
+
self._error_count += 1
|
91
|
+
execution_time = time.time() - start_time
|
92
|
+
|
93
|
+
return ExecutionResult(
|
94
|
+
data=None,
|
95
|
+
success=False,
|
96
|
+
error=str(e),
|
97
|
+
execution_time=execution_time
|
98
|
+
)
|
99
|
+
|
100
|
+
@abstractmethod
|
101
|
+
def _do_execute(self, action: Action, context: ExecutionContext) -> ExecutionResult:
|
102
|
+
"""
|
103
|
+
Execute the actual operation (implemented by subclasses).
|
104
|
+
|
105
|
+
Args:
|
106
|
+
action: The action to execute
|
107
|
+
context: Execution context
|
108
|
+
|
109
|
+
Returns:
|
110
|
+
ExecutionResult with data
|
111
|
+
"""
|
112
|
+
pass
|
113
|
+
|
114
|
+
def validate(self, action: Action, context: ExecutionContext) -> bool:
|
115
|
+
"""
|
116
|
+
Validate action before execution.
|
117
|
+
|
118
|
+
Default implementation checks basic requirements.
|
119
|
+
Subclasses can override for specific validation.
|
120
|
+
"""
|
121
|
+
if not action or not action.type:
|
122
|
+
return False
|
123
|
+
if not context or not context.node:
|
124
|
+
return False
|
125
|
+
return True
|
126
|
+
|
127
|
+
def can_execute_on(self, node_type: NodeType) -> bool:
|
128
|
+
"""
|
129
|
+
Check if this executor can operate on the given node type.
|
130
|
+
|
131
|
+
Args:
|
132
|
+
node_type: The node type to check
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
True if this executor supports the node type
|
136
|
+
"""
|
137
|
+
# Empty list means supports all types (universal operation)
|
138
|
+
if not self.SUPPORTED_NODE_TYPES:
|
139
|
+
return True
|
140
|
+
return node_type in self.SUPPORTED_NODE_TYPES
|
141
|
+
|
142
|
+
def validate_capability_or_raise(self, context: ExecutionContext) -> None:
|
143
|
+
"""
|
144
|
+
Validate operation can execute on node, raise if not.
|
145
|
+
|
146
|
+
Args:
|
147
|
+
context: Execution context
|
148
|
+
|
149
|
+
Raises:
|
150
|
+
UnsupportedOperationError: If operation cannot execute on node type
|
151
|
+
"""
|
152
|
+
# Get node's strategy type
|
153
|
+
if hasattr(context.node, '_strategy') and hasattr(context.node._strategy, 'STRATEGY_TYPE'):
|
154
|
+
node_type = context.node._strategy.STRATEGY_TYPE
|
155
|
+
elif hasattr(context.node, 'STRATEGY_TYPE'):
|
156
|
+
node_type = context.node.STRATEGY_TYPE
|
157
|
+
else:
|
158
|
+
# Default to TREE for backward compatibility
|
159
|
+
node_type = NodeType.TREE
|
160
|
+
|
161
|
+
# Check if operation can execute on this node type
|
162
|
+
if not self.can_execute_on(node_type):
|
163
|
+
supported = [nt.name for nt in self.SUPPORTED_NODE_TYPES]
|
164
|
+
raise UnsupportedOperationError(
|
165
|
+
self.OPERATION_NAME,
|
166
|
+
node_type,
|
167
|
+
f"Requires one of: {supported}"
|
168
|
+
)
|
169
|
+
|
170
|
+
def estimate_cost(self, action: Action, context: ExecutionContext) -> int:
|
171
|
+
"""
|
172
|
+
Estimate execution cost.
|
173
|
+
|
174
|
+
Default implementation returns fixed cost.
|
175
|
+
Subclasses can override for more accurate estimates.
|
176
|
+
"""
|
177
|
+
return 100
|
178
|
+
|
179
|
+
def get_stats(self) -> Dict[str, Any]:
|
180
|
+
"""Get execution statistics for this executor."""
|
181
|
+
avg_time = self._total_time / self._execution_count if self._execution_count > 0 else 0
|
182
|
+
|
183
|
+
return {
|
184
|
+
'operation': self.OPERATION_NAME,
|
185
|
+
'execution_count': self._execution_count,
|
186
|
+
'total_time': self._total_time,
|
187
|
+
'average_time': avg_time,
|
188
|
+
'error_count': self._error_count,
|
189
|
+
'success_rate': (self._execution_count - self._error_count) / self._execution_count if self._execution_count > 0 else 1.0
|
190
|
+
}
|
191
|
+
|
192
|
+
|
193
|
+
class AUniversalOperationExecutor(AOperationExecutor):
|
194
|
+
"""
|
195
|
+
Base class for universal operations that work on all node types.
|
196
|
+
|
197
|
+
Universal operations:
|
198
|
+
- SELECT, INSERT, UPDATE, DELETE
|
199
|
+
- WHERE, FILTER
|
200
|
+
- GROUP BY, COUNT, SUM, AVG
|
201
|
+
- PROJECT, EXTEND
|
202
|
+
"""
|
203
|
+
|
204
|
+
# Universal operations support all node types (empty list)
|
205
|
+
SUPPORTED_NODE_TYPES: List[NodeType] = []
|
206
|
+
|
207
|
+
|
208
|
+
class ATreeOperationExecutor(AOperationExecutor):
|
209
|
+
"""
|
210
|
+
Base class for tree-specific operations.
|
211
|
+
|
212
|
+
Tree operations:
|
213
|
+
- BETWEEN, RANGE
|
214
|
+
- ORDER BY
|
215
|
+
- MIN, MAX (optimal on trees)
|
216
|
+
"""
|
217
|
+
|
218
|
+
# Only works on tree nodes
|
219
|
+
SUPPORTED_NODE_TYPES: List[NodeType] = [NodeType.TREE]
|
220
|
+
REQUIRED_CAPABILITIES: OperationCapability = OperationCapability.REQUIRES_ORDERED
|
221
|
+
|
222
|
+
|
223
|
+
class AGraphOperationExecutor(AOperationExecutor):
|
224
|
+
"""
|
225
|
+
Base class for graph-specific operations.
|
226
|
+
|
227
|
+
Graph operations:
|
228
|
+
- MATCH, PATH
|
229
|
+
- OUT, IN_TRAVERSE
|
230
|
+
- Graph traversal
|
231
|
+
"""
|
232
|
+
|
233
|
+
# Only works on graph nodes
|
234
|
+
SUPPORTED_NODE_TYPES: List[NodeType] = [NodeType.GRAPH, NodeType.TREE] # Trees can act as graphs
|
235
|
+
|
236
|
+
|
237
|
+
class ALinearOperationExecutor(AOperationExecutor):
|
238
|
+
"""
|
239
|
+
Base class for linear-specific operations.
|
240
|
+
|
241
|
+
Linear operations:
|
242
|
+
- SLICING, INDEXING
|
243
|
+
- Sequential operations
|
244
|
+
"""
|
245
|
+
|
246
|
+
# Only works on linear and matrix nodes
|
247
|
+
SUPPORTED_NODE_TYPES: List[NodeType] = [NodeType.LINEAR, NodeType.MATRIX]
|
248
|
+
|
249
|
+
|
250
|
+
__all__ = [
|
251
|
+
'AOperationExecutor',
|
252
|
+
'AUniversalOperationExecutor',
|
253
|
+
'ATreeOperationExecutor',
|
254
|
+
'AGraphOperationExecutor',
|
255
|
+
'ALinearOperationExecutor',
|
256
|
+
'UnsupportedOperationError',
|
257
|
+
]
|
@@ -0,0 +1,204 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
#exonware/xwnode/src/exonware/xwnode/queries/executors/capability_checker.py
|
4
|
+
|
5
|
+
Operation Capability Checker
|
6
|
+
|
7
|
+
This module provides capability checking for operations on different node types.
|
8
|
+
|
9
|
+
Company: eXonware.com
|
10
|
+
Author: Eng. Muhammad AlShehri
|
11
|
+
Email: connect@exonware.com
|
12
|
+
Version: 0.0.1.15
|
13
|
+
Generation Date: 08-Oct-2025
|
14
|
+
"""
|
15
|
+
|
16
|
+
from typing import Dict, List, Set
|
17
|
+
|
18
|
+
# Import NodeType from nodes module per DEV_GUIDELINES
|
19
|
+
from ...nodes.strategies.contracts import NodeType
|
20
|
+
|
21
|
+
|
22
|
+
# Operation-to-NodeType Compatibility Matrix
|
23
|
+
OPERATION_COMPATIBILITY = {
|
24
|
+
# Core CRUD Operations (Universal)
|
25
|
+
'SELECT': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
26
|
+
'INSERT': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
27
|
+
'UPDATE': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
28
|
+
'DELETE': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
29
|
+
'CREATE': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
30
|
+
'DROP': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
31
|
+
|
32
|
+
# Filtering Operations (Universal)
|
33
|
+
'WHERE': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
34
|
+
'FILTER': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
35
|
+
'LIKE': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
36
|
+
'IN': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
37
|
+
'HAS': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
38
|
+
|
39
|
+
# Range Operations (Tree/Matrix)
|
40
|
+
'BETWEEN': {NodeType.TREE, NodeType.MATRIX},
|
41
|
+
'RANGE': {NodeType.TREE, NodeType.MATRIX},
|
42
|
+
|
43
|
+
# Aggregation Operations (Universal)
|
44
|
+
'GROUP': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
45
|
+
'BY': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
46
|
+
'HAVING': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
47
|
+
'SUMMARIZE': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
48
|
+
'SUM': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
49
|
+
'COUNT': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
50
|
+
'AVG': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
51
|
+
'MIN': {NodeType.LINEAR, NodeType.TREE, NodeType.MATRIX}, # Optimal on trees
|
52
|
+
'MAX': {NodeType.LINEAR, NodeType.TREE, NodeType.MATRIX}, # Optimal on trees
|
53
|
+
'DISTINCT': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
54
|
+
|
55
|
+
# Ordering Operations (Tree/Linear)
|
56
|
+
'ORDER': {NodeType.TREE, NodeType.LINEAR},
|
57
|
+
|
58
|
+
# Join Operations (Universal conceptually)
|
59
|
+
'JOIN': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
60
|
+
'UNION': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
61
|
+
'WITH': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
62
|
+
'OPTIONAL': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
63
|
+
|
64
|
+
# Graph Operations
|
65
|
+
'MATCH': {NodeType.GRAPH, NodeType.TREE, NodeType.HYBRID},
|
66
|
+
'PATH': {NodeType.GRAPH, NodeType.TREE, NodeType.HYBRID},
|
67
|
+
'OUT': {NodeType.GRAPH, NodeType.TREE, NodeType.HYBRID},
|
68
|
+
'IN_TRAVERSE': {NodeType.GRAPH, NodeType.TREE, NodeType.HYBRID},
|
69
|
+
'RETURN': {NodeType.GRAPH, NodeType.TREE, NodeType.HYBRID},
|
70
|
+
|
71
|
+
# Projection Operations (Universal)
|
72
|
+
'PROJECT': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
73
|
+
'EXTEND': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
74
|
+
|
75
|
+
# Array Operations (Linear/Matrix)
|
76
|
+
'SLICING': {NodeType.LINEAR, NodeType.MATRIX},
|
77
|
+
'INDEXING': {NodeType.LINEAR, NodeType.MATRIX, NodeType.TREE},
|
78
|
+
|
79
|
+
# Search Operations (Universal)
|
80
|
+
'TERM': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
81
|
+
|
82
|
+
# Data Operations (Universal)
|
83
|
+
'LOAD': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
84
|
+
'STORE': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
85
|
+
'MERGE': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
86
|
+
'ALTER': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
87
|
+
|
88
|
+
# Control Flow Operations (Universal)
|
89
|
+
'FOREACH': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
90
|
+
'LET': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
91
|
+
'FOR': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
92
|
+
|
93
|
+
# Window Operations (Time-series, works on linear/tree)
|
94
|
+
'WINDOW': {NodeType.LINEAR, NodeType.TREE},
|
95
|
+
'AGGREGATE': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
96
|
+
|
97
|
+
# Metadata Operations (Universal)
|
98
|
+
'DESCRIBE': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
99
|
+
'CONSTRUCT': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
100
|
+
'ASK': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
101
|
+
|
102
|
+
# Advanced Operations (Universal)
|
103
|
+
'SUBSCRIBE': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
104
|
+
'SUBSCRIPTION': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
105
|
+
'MUTATION': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
106
|
+
'PIPE': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
107
|
+
'OPTIONS': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
108
|
+
'VALUES': {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID},
|
109
|
+
}
|
110
|
+
|
111
|
+
|
112
|
+
def check_operation_compatibility(operation: str, node_type: NodeType) -> bool:
|
113
|
+
"""
|
114
|
+
Check if an operation is compatible with a node type.
|
115
|
+
|
116
|
+
Args:
|
117
|
+
operation: Operation name (e.g., "SELECT")
|
118
|
+
node_type: Node type to check
|
119
|
+
|
120
|
+
Returns:
|
121
|
+
True if operation is compatible with node type
|
122
|
+
"""
|
123
|
+
operation = operation.upper()
|
124
|
+
|
125
|
+
# Check compatibility matrix
|
126
|
+
if operation in OPERATION_COMPATIBILITY:
|
127
|
+
return node_type in OPERATION_COMPATIBILITY[operation]
|
128
|
+
|
129
|
+
# Unknown operation - assume universal (backward compatibility)
|
130
|
+
return True
|
131
|
+
|
132
|
+
|
133
|
+
def get_supported_operations(node_type: NodeType) -> List[str]:
|
134
|
+
"""
|
135
|
+
Get list of operations supported by a node type.
|
136
|
+
|
137
|
+
Args:
|
138
|
+
node_type: Node type to check
|
139
|
+
|
140
|
+
Returns:
|
141
|
+
List of supported operation names
|
142
|
+
"""
|
143
|
+
supported = []
|
144
|
+
|
145
|
+
for operation, compatible_types in OPERATION_COMPATIBILITY.items():
|
146
|
+
if node_type in compatible_types:
|
147
|
+
supported.append(operation)
|
148
|
+
|
149
|
+
return supported
|
150
|
+
|
151
|
+
|
152
|
+
def get_universal_operations() -> List[str]:
|
153
|
+
"""
|
154
|
+
Get list of universal operations (work on all node types).
|
155
|
+
|
156
|
+
Returns:
|
157
|
+
List of universal operation names
|
158
|
+
"""
|
159
|
+
universal = []
|
160
|
+
all_types = {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID}
|
161
|
+
|
162
|
+
for operation, compatible_types in OPERATION_COMPATIBILITY.items():
|
163
|
+
if compatible_types == all_types:
|
164
|
+
universal.append(operation)
|
165
|
+
|
166
|
+
return universal
|
167
|
+
|
168
|
+
|
169
|
+
def get_type_specific_operations(node_type: NodeType) -> List[str]:
|
170
|
+
"""
|
171
|
+
Get operations that are specific to (or optimal for) a node type.
|
172
|
+
|
173
|
+
Args:
|
174
|
+
node_type: Node type to check
|
175
|
+
|
176
|
+
Returns:
|
177
|
+
List of type-specific operation names
|
178
|
+
"""
|
179
|
+
specific = []
|
180
|
+
all_types = {NodeType.LINEAR, NodeType.TREE, NodeType.GRAPH, NodeType.MATRIX, NodeType.HYBRID}
|
181
|
+
|
182
|
+
for operation, compatible_types in OPERATION_COMPATIBILITY.items():
|
183
|
+
# If node type supports it but not all types support it
|
184
|
+
if node_type in compatible_types and compatible_types != all_types:
|
185
|
+
specific.append(operation)
|
186
|
+
|
187
|
+
return specific
|
188
|
+
|
189
|
+
|
190
|
+
# Global registry accessor
|
191
|
+
def get_global_registry() -> OperationRegistry:
|
192
|
+
"""Get the global operation registry instance."""
|
193
|
+
return OperationRegistry()
|
194
|
+
|
195
|
+
|
196
|
+
__all__ = [
|
197
|
+
'OperationRegistry',
|
198
|
+
'get_operation_registry',
|
199
|
+
'check_operation_compatibility',
|
200
|
+
'get_supported_operations',
|
201
|
+
'get_universal_operations',
|
202
|
+
'get_type_specific_operations',
|
203
|
+
'OPERATION_COMPATIBILITY',
|
204
|
+
]
|
@@ -0,0 +1,166 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
#exonware/xwnode/src/exonware/xwnode/queries/executors/contracts.py
|
4
|
+
|
5
|
+
Operation Executor Contracts
|
6
|
+
|
7
|
+
This module defines the interfaces and data structures for query operation execution.
|
8
|
+
|
9
|
+
Company: eXonware.com
|
10
|
+
Author: Eng. Muhammad AlShehri
|
11
|
+
Email: connect@exonware.com
|
12
|
+
Version: 0.0.1.15
|
13
|
+
Generation Date: 08-Oct-2025
|
14
|
+
"""
|
15
|
+
|
16
|
+
from abc import ABC, abstractmethod
|
17
|
+
from typing import Any, Dict, List, Optional
|
18
|
+
from dataclasses import dataclass, field
|
19
|
+
|
20
|
+
# Import shared types per DEV_GUIDELINES.md
|
21
|
+
from ...nodes.strategies.contracts import NodeType
|
22
|
+
from .types import OperationCapability
|
23
|
+
|
24
|
+
|
25
|
+
@dataclass
|
26
|
+
class Action:
|
27
|
+
"""
|
28
|
+
Represents a single query action to be executed.
|
29
|
+
|
30
|
+
Actions are parsed from XWQuery Script and contain all information
|
31
|
+
needed to execute a specific operation.
|
32
|
+
"""
|
33
|
+
type: str # e.g., "SELECT", "INSERT", "WHERE"
|
34
|
+
params: Dict[str, Any] # Operation parameters
|
35
|
+
id: str = "" # Unique action ID
|
36
|
+
line_number: int = 0 # Source line number
|
37
|
+
children: List['Action'] = field(default_factory=list) # Nested actions
|
38
|
+
metadata: Dict[str, Any] = field(default_factory=dict) # Additional metadata
|
39
|
+
|
40
|
+
|
41
|
+
@dataclass
|
42
|
+
class ExecutionContext:
|
43
|
+
"""
|
44
|
+
Execution context for operation execution.
|
45
|
+
|
46
|
+
Contains all state needed during execution including the target node,
|
47
|
+
variables, transaction state, and configuration.
|
48
|
+
"""
|
49
|
+
node: Any # Target XWNode to execute on
|
50
|
+
variables: Dict[str, Any] = field(default_factory=dict) # Query variables
|
51
|
+
transaction: Optional[Any] = None # Transaction object (if in transaction)
|
52
|
+
cache: Optional[Dict[str, Any]] = None # Result cache
|
53
|
+
parent_results: Dict[str, Any] = field(default_factory=dict) # Results from parent actions
|
54
|
+
options: Dict[str, Any] = field(default_factory=dict) # Execution options
|
55
|
+
|
56
|
+
def set_result(self, action_id: str, result: Any) -> None:
|
57
|
+
"""Store result for later use by other actions."""
|
58
|
+
self.parent_results[action_id] = result
|
59
|
+
|
60
|
+
def get_result(self, action_id: str) -> Optional[Any]:
|
61
|
+
"""Get result from previous action."""
|
62
|
+
return self.parent_results.get(action_id)
|
63
|
+
|
64
|
+
|
65
|
+
@dataclass
|
66
|
+
class ExecutionResult:
|
67
|
+
"""
|
68
|
+
Result of operation execution.
|
69
|
+
|
70
|
+
Contains the data returned by the operation along with metadata
|
71
|
+
about the execution.
|
72
|
+
"""
|
73
|
+
data: Any # Result data
|
74
|
+
affected_count: int = 0 # Number of items affected
|
75
|
+
execution_time: float = 0.0 # Execution time in seconds
|
76
|
+
metadata: Dict[str, Any] = field(default_factory=dict) # Additional metadata
|
77
|
+
success: bool = True # Whether execution succeeded
|
78
|
+
error: Optional[str] = None # Error message if failed
|
79
|
+
|
80
|
+
|
81
|
+
class IOperationExecutor(ABC):
|
82
|
+
"""
|
83
|
+
Interface for operation executors.
|
84
|
+
|
85
|
+
All operation executors must implement this interface to be compatible
|
86
|
+
with the execution engine.
|
87
|
+
"""
|
88
|
+
|
89
|
+
# Operation name (e.g., "SELECT", "INSERT")
|
90
|
+
OPERATION_NAME: str = ""
|
91
|
+
|
92
|
+
# Supported node types (empty = all types)
|
93
|
+
SUPPORTED_NODE_TYPES: List[NodeType] = []
|
94
|
+
|
95
|
+
# Required capabilities
|
96
|
+
REQUIRED_CAPABILITIES: OperationCapability = OperationCapability.NONE
|
97
|
+
|
98
|
+
@abstractmethod
|
99
|
+
def execute(self, action: Action, context: ExecutionContext) -> ExecutionResult:
|
100
|
+
"""
|
101
|
+
Execute the operation.
|
102
|
+
|
103
|
+
Args:
|
104
|
+
action: The action to execute
|
105
|
+
context: Execution context with node and state
|
106
|
+
|
107
|
+
Returns:
|
108
|
+
ExecutionResult with data and metadata
|
109
|
+
|
110
|
+
Raises:
|
111
|
+
UnsupportedOperationError: If operation cannot execute on node type
|
112
|
+
ExecutionError: If execution fails
|
113
|
+
"""
|
114
|
+
pass
|
115
|
+
|
116
|
+
@abstractmethod
|
117
|
+
def validate(self, action: Action, context: ExecutionContext) -> bool:
|
118
|
+
"""
|
119
|
+
Validate that the action can be executed.
|
120
|
+
|
121
|
+
Args:
|
122
|
+
action: The action to validate
|
123
|
+
context: Execution context
|
124
|
+
|
125
|
+
Returns:
|
126
|
+
True if action is valid and can be executed
|
127
|
+
"""
|
128
|
+
pass
|
129
|
+
|
130
|
+
def can_execute_on(self, node_type: NodeType) -> bool:
|
131
|
+
"""
|
132
|
+
Check if this executor can operate on the given node type.
|
133
|
+
|
134
|
+
Args:
|
135
|
+
node_type: The node type to check
|
136
|
+
|
137
|
+
Returns:
|
138
|
+
True if this executor supports the node type
|
139
|
+
"""
|
140
|
+
# Empty list means supports all types
|
141
|
+
if not self.SUPPORTED_NODE_TYPES:
|
142
|
+
return True
|
143
|
+
return node_type in self.SUPPORTED_NODE_TYPES
|
144
|
+
|
145
|
+
def estimate_cost(self, action: Action, context: ExecutionContext) -> int:
|
146
|
+
"""
|
147
|
+
Estimate execution cost (optional).
|
148
|
+
|
149
|
+
Args:
|
150
|
+
action: The action to estimate
|
151
|
+
context: Execution context
|
152
|
+
|
153
|
+
Returns:
|
154
|
+
Estimated cost (arbitrary units)
|
155
|
+
"""
|
156
|
+
return 100 # Default cost
|
157
|
+
|
158
|
+
|
159
|
+
__all__ = [
|
160
|
+
'IOperationExecutor',
|
161
|
+
'Action',
|
162
|
+
'ExecutionContext',
|
163
|
+
'ExecutionResult',
|
164
|
+
'OperationCapability',
|
165
|
+
'NodeType',
|
166
|
+
]
|
@@ -0,0 +1,17 @@
|
|
1
|
+
"""Core CRUD operation executors."""
|
2
|
+
|
3
|
+
from .select_executor import SelectExecutor
|
4
|
+
from .insert_executor import InsertExecutor
|
5
|
+
from .update_executor import UpdateExecutor
|
6
|
+
from .delete_executor import DeleteExecutor
|
7
|
+
from .create_executor import CreateExecutor
|
8
|
+
from .drop_executor import DropExecutor
|
9
|
+
|
10
|
+
__all__ = [
|
11
|
+
'SelectExecutor',
|
12
|
+
'InsertExecutor',
|
13
|
+
'UpdateExecutor',
|
14
|
+
'DeleteExecutor',
|
15
|
+
'CreateExecutor',
|
16
|
+
'DropExecutor',
|
17
|
+
]
|