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.
Files changed (132) hide show
  1. exonware/__init__.py +14 -0
  2. exonware/xwnode/__init__.py +127 -0
  3. exonware/xwnode/base.py +676 -0
  4. exonware/xwnode/config.py +178 -0
  5. exonware/xwnode/contracts.py +730 -0
  6. exonware/xwnode/errors.py +503 -0
  7. exonware/xwnode/facade.py +460 -0
  8. exonware/xwnode/strategies/__init__.py +158 -0
  9. exonware/xwnode/strategies/advisor.py +463 -0
  10. exonware/xwnode/strategies/edges/__init__.py +32 -0
  11. exonware/xwnode/strategies/edges/adj_list.py +227 -0
  12. exonware/xwnode/strategies/edges/adj_matrix.py +391 -0
  13. exonware/xwnode/strategies/edges/base.py +169 -0
  14. exonware/xwnode/strategies/flyweight.py +328 -0
  15. exonware/xwnode/strategies/impls/__init__.py +13 -0
  16. exonware/xwnode/strategies/impls/_base_edge.py +403 -0
  17. exonware/xwnode/strategies/impls/_base_node.py +307 -0
  18. exonware/xwnode/strategies/impls/edge_adj_list.py +353 -0
  19. exonware/xwnode/strategies/impls/edge_adj_matrix.py +445 -0
  20. exonware/xwnode/strategies/impls/edge_bidir_wrapper.py +455 -0
  21. exonware/xwnode/strategies/impls/edge_block_adj_matrix.py +539 -0
  22. exonware/xwnode/strategies/impls/edge_coo.py +533 -0
  23. exonware/xwnode/strategies/impls/edge_csc.py +447 -0
  24. exonware/xwnode/strategies/impls/edge_csr.py +492 -0
  25. exonware/xwnode/strategies/impls/edge_dynamic_adj_list.py +503 -0
  26. exonware/xwnode/strategies/impls/edge_flow_network.py +555 -0
  27. exonware/xwnode/strategies/impls/edge_hyperedge_set.py +516 -0
  28. exonware/xwnode/strategies/impls/edge_neural_graph.py +650 -0
  29. exonware/xwnode/strategies/impls/edge_octree.py +574 -0
  30. exonware/xwnode/strategies/impls/edge_property_store.py +655 -0
  31. exonware/xwnode/strategies/impls/edge_quadtree.py +519 -0
  32. exonware/xwnode/strategies/impls/edge_rtree.py +820 -0
  33. exonware/xwnode/strategies/impls/edge_temporal_edgeset.py +558 -0
  34. exonware/xwnode/strategies/impls/edge_tree_graph_basic.py +271 -0
  35. exonware/xwnode/strategies/impls/edge_weighted_graph.py +411 -0
  36. exonware/xwnode/strategies/manager.py +775 -0
  37. exonware/xwnode/strategies/metrics.py +538 -0
  38. exonware/xwnode/strategies/migration.py +432 -0
  39. exonware/xwnode/strategies/nodes/__init__.py +50 -0
  40. exonware/xwnode/strategies/nodes/_base_node.py +307 -0
  41. exonware/xwnode/strategies/nodes/adjacency_list.py +267 -0
  42. exonware/xwnode/strategies/nodes/aho_corasick.py +345 -0
  43. exonware/xwnode/strategies/nodes/array_list.py +209 -0
  44. exonware/xwnode/strategies/nodes/base.py +247 -0
  45. exonware/xwnode/strategies/nodes/deque.py +200 -0
  46. exonware/xwnode/strategies/nodes/hash_map.py +135 -0
  47. exonware/xwnode/strategies/nodes/heap.py +307 -0
  48. exonware/xwnode/strategies/nodes/linked_list.py +232 -0
  49. exonware/xwnode/strategies/nodes/node_aho_corasick.py +520 -0
  50. exonware/xwnode/strategies/nodes/node_array_list.py +175 -0
  51. exonware/xwnode/strategies/nodes/node_avl_tree.py +371 -0
  52. exonware/xwnode/strategies/nodes/node_b_plus_tree.py +542 -0
  53. exonware/xwnode/strategies/nodes/node_bitmap.py +420 -0
  54. exonware/xwnode/strategies/nodes/node_bitset_dynamic.py +513 -0
  55. exonware/xwnode/strategies/nodes/node_bloom_filter.py +347 -0
  56. exonware/xwnode/strategies/nodes/node_btree.py +357 -0
  57. exonware/xwnode/strategies/nodes/node_count_min_sketch.py +470 -0
  58. exonware/xwnode/strategies/nodes/node_cow_tree.py +473 -0
  59. exonware/xwnode/strategies/nodes/node_cuckoo_hash.py +392 -0
  60. exonware/xwnode/strategies/nodes/node_fenwick_tree.py +301 -0
  61. exonware/xwnode/strategies/nodes/node_hash_map.py +269 -0
  62. exonware/xwnode/strategies/nodes/node_heap.py +191 -0
  63. exonware/xwnode/strategies/nodes/node_hyperloglog.py +407 -0
  64. exonware/xwnode/strategies/nodes/node_linked_list.py +409 -0
  65. exonware/xwnode/strategies/nodes/node_lsm_tree.py +400 -0
  66. exonware/xwnode/strategies/nodes/node_ordered_map.py +390 -0
  67. exonware/xwnode/strategies/nodes/node_ordered_map_balanced.py +565 -0
  68. exonware/xwnode/strategies/nodes/node_patricia.py +512 -0
  69. exonware/xwnode/strategies/nodes/node_persistent_tree.py +378 -0
  70. exonware/xwnode/strategies/nodes/node_radix_trie.py +452 -0
  71. exonware/xwnode/strategies/nodes/node_red_black_tree.py +497 -0
  72. exonware/xwnode/strategies/nodes/node_roaring_bitmap.py +570 -0
  73. exonware/xwnode/strategies/nodes/node_segment_tree.py +289 -0
  74. exonware/xwnode/strategies/nodes/node_set_hash.py +354 -0
  75. exonware/xwnode/strategies/nodes/node_set_tree.py +480 -0
  76. exonware/xwnode/strategies/nodes/node_skip_list.py +316 -0
  77. exonware/xwnode/strategies/nodes/node_splay_tree.py +393 -0
  78. exonware/xwnode/strategies/nodes/node_suffix_array.py +487 -0
  79. exonware/xwnode/strategies/nodes/node_treap.py +387 -0
  80. exonware/xwnode/strategies/nodes/node_tree_graph_hybrid.py +1434 -0
  81. exonware/xwnode/strategies/nodes/node_trie.py +252 -0
  82. exonware/xwnode/strategies/nodes/node_union_find.py +187 -0
  83. exonware/xwnode/strategies/nodes/node_xdata_optimized.py +369 -0
  84. exonware/xwnode/strategies/nodes/priority_queue.py +209 -0
  85. exonware/xwnode/strategies/nodes/queue.py +161 -0
  86. exonware/xwnode/strategies/nodes/sparse_matrix.py +206 -0
  87. exonware/xwnode/strategies/nodes/stack.py +152 -0
  88. exonware/xwnode/strategies/nodes/trie.py +274 -0
  89. exonware/xwnode/strategies/nodes/union_find.py +283 -0
  90. exonware/xwnode/strategies/pattern_detector.py +603 -0
  91. exonware/xwnode/strategies/performance_monitor.py +487 -0
  92. exonware/xwnode/strategies/queries/__init__.py +24 -0
  93. exonware/xwnode/strategies/queries/base.py +236 -0
  94. exonware/xwnode/strategies/queries/cql.py +201 -0
  95. exonware/xwnode/strategies/queries/cypher.py +181 -0
  96. exonware/xwnode/strategies/queries/datalog.py +70 -0
  97. exonware/xwnode/strategies/queries/elastic_dsl.py +70 -0
  98. exonware/xwnode/strategies/queries/eql.py +70 -0
  99. exonware/xwnode/strategies/queries/flux.py +70 -0
  100. exonware/xwnode/strategies/queries/gql.py +70 -0
  101. exonware/xwnode/strategies/queries/graphql.py +240 -0
  102. exonware/xwnode/strategies/queries/gremlin.py +181 -0
  103. exonware/xwnode/strategies/queries/hiveql.py +214 -0
  104. exonware/xwnode/strategies/queries/hql.py +70 -0
  105. exonware/xwnode/strategies/queries/jmespath.py +219 -0
  106. exonware/xwnode/strategies/queries/jq.py +66 -0
  107. exonware/xwnode/strategies/queries/json_query.py +66 -0
  108. exonware/xwnode/strategies/queries/jsoniq.py +248 -0
  109. exonware/xwnode/strategies/queries/kql.py +70 -0
  110. exonware/xwnode/strategies/queries/linq.py +238 -0
  111. exonware/xwnode/strategies/queries/logql.py +70 -0
  112. exonware/xwnode/strategies/queries/mql.py +68 -0
  113. exonware/xwnode/strategies/queries/n1ql.py +210 -0
  114. exonware/xwnode/strategies/queries/partiql.py +70 -0
  115. exonware/xwnode/strategies/queries/pig.py +215 -0
  116. exonware/xwnode/strategies/queries/promql.py +70 -0
  117. exonware/xwnode/strategies/queries/sparql.py +220 -0
  118. exonware/xwnode/strategies/queries/sql.py +275 -0
  119. exonware/xwnode/strategies/queries/xml_query.py +66 -0
  120. exonware/xwnode/strategies/queries/xpath.py +223 -0
  121. exonware/xwnode/strategies/queries/xquery.py +258 -0
  122. exonware/xwnode/strategies/queries/xwnode_executor.py +332 -0
  123. exonware/xwnode/strategies/queries/xwquery_strategy.py +424 -0
  124. exonware/xwnode/strategies/registry.py +604 -0
  125. exonware/xwnode/strategies/simple.py +273 -0
  126. exonware/xwnode/strategies/utils.py +532 -0
  127. exonware/xwnode/types.py +912 -0
  128. exonware/xwnode/version.py +78 -0
  129. exonware_xwnode-0.0.1.12.dist-info/METADATA +169 -0
  130. exonware_xwnode-0.0.1.12.dist-info/RECORD +132 -0
  131. exonware_xwnode-0.0.1.12.dist-info/WHEEL +4 -0
  132. exonware_xwnode-0.0.1.12.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,676 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ #exonware/xwnode/src/exonware/xwnode/base.py
4
+
5
+ Abstract base classes for XWNode.
6
+
7
+ This module contains the abstract base classes that provide core functionality
8
+ for all XWNode implementations.
9
+ """
10
+
11
+ import threading
12
+ import copy
13
+ from abc import ABC
14
+ from typing import Any, Iterator, Union, Optional, List, Dict, Callable
15
+ from collections import OrderedDict
16
+
17
+ # Core XWNode imports - strategy-agnostic
18
+ from .errors import (
19
+ XWNodeTypeError, XWNodePathError, XWNodeSecurityError, XWNodeValueError, XWNodeLimitError
20
+ )
21
+ from .config import get_config
22
+ from .contracts import iNodeFacade, iNodeStrategy, iEdge, iEdgeStrategy, iQuery, iQueryResult, iQueryEngine
23
+
24
+ # System-level imports - standard imports (no defensive code!)
25
+ from exonware.xwsystem.security import get_resource_limits
26
+ from exonware.xwsystem.validation import validate_untrusted_data
27
+ from exonware.xwsystem.monitoring import create_component_metrics
28
+ from exonware.xwsystem.threading import ThreadSafeFactory, create_thread_safe_cache
29
+ from exonware.xwsystem.patterns import CircuitBreaker
30
+ from exonware.xwsystem import get_logger
31
+
32
+ logger = get_logger('xwnode.base')
33
+
34
+ # Metrics setup
35
+ _metrics = create_component_metrics('xwnode_base')
36
+ measure_operation = _metrics['measure_operation']
37
+ record_cache_hit = _metrics['record_cache_hit']
38
+ record_cache_miss = _metrics['record_cache_miss']
39
+
40
+ # Thread-safe cache for path parsing
41
+ _path_cache = create_thread_safe_cache(max_size=1024)
42
+
43
+ # Circuit breaker for strategy operations
44
+ _strategy_circuit_breaker = CircuitBreaker(
45
+ failure_threshold=5,
46
+ recovery_timeout=30,
47
+ expected_exception=Exception
48
+ )
49
+
50
+
51
+ class PathParser:
52
+ """Thread-safe path parser with caching."""
53
+
54
+ def __init__(self, max_cache_size: int = 1024):
55
+ self._cache = OrderedDict()
56
+ self._max_cache_size = max_cache_size
57
+ self._lock = threading.RLock()
58
+
59
+ def parse(self, path: str) -> List[str]:
60
+ """Parse a path string into parts."""
61
+ with self._lock:
62
+ if path in self._cache:
63
+ record_cache_hit()
64
+ return self._cache[path]
65
+
66
+ record_cache_miss()
67
+ parts = self._parse_path(path)
68
+
69
+ # Cache the result
70
+ if len(self._cache) >= self._max_cache_size:
71
+ self._cache.popitem(last=False)
72
+ self._cache[path] = parts
73
+
74
+ return parts
75
+
76
+ def _parse_path(self, path: str) -> List[str]:
77
+ """Internal path parsing logic."""
78
+ if not path:
79
+ return []
80
+
81
+ parts = []
82
+ current = ""
83
+ in_brackets = False
84
+ in_quotes = False
85
+ quote_char = None
86
+
87
+ for char in path:
88
+ if in_quotes:
89
+ if char == quote_char:
90
+ in_quotes = False
91
+ quote_char = None
92
+ else:
93
+ current += char
94
+ elif char in ['"', "'"]:
95
+ in_quotes = True
96
+ quote_char = char
97
+ elif char == '[':
98
+ if current:
99
+ parts.append(current)
100
+ current = ""
101
+ in_brackets = True
102
+ current += char
103
+ elif char == ']':
104
+ current += char
105
+ in_brackets = False
106
+ elif char == '.' and not in_brackets:
107
+ if current:
108
+ parts.append(current)
109
+ current = ""
110
+ else:
111
+ current += char
112
+
113
+ if current:
114
+ parts.append(current)
115
+
116
+ return parts
117
+
118
+ def clear_cache(self):
119
+ """Clear the path cache."""
120
+ with self._lock:
121
+ self._cache.clear()
122
+
123
+
124
+ class GlobalPathCache:
125
+ """Global cache for path lookups."""
126
+
127
+ def __init__(self, max_size: int = 512):
128
+ self._cache = OrderedDict()
129
+ self._max_size = max_size
130
+ self._lock = threading.RLock()
131
+ self._stats = {'hits': 0, 'misses': 0}
132
+
133
+ def get(self, node_id: int, path: str) -> Optional[Any]:
134
+ """Get cached result for node and path."""
135
+ key = (node_id, path)
136
+ with self._lock:
137
+ if key in self._cache:
138
+ self._stats['hits'] += 1
139
+ return self._cache[key]
140
+ self._stats['misses'] += 1
141
+ return None
142
+
143
+ def put(self, node_id: int, path: str, result: Any):
144
+ """Cache result for node and path."""
145
+ key = (node_id, path)
146
+ with self._lock:
147
+ if len(self._cache) >= self._max_size:
148
+ self._cache.popitem(last=False)
149
+ self._cache[key] = result
150
+
151
+ def clear(self):
152
+ """Clear the cache."""
153
+ with self._lock:
154
+ self._cache.clear()
155
+
156
+ def stats(self) -> Dict[str, int]:
157
+ """Get cache statistics."""
158
+ with self._lock:
159
+ return self._stats.copy()
160
+
161
+
162
+ # Global instances
163
+ _path_parser = None
164
+ _global_path_cache = None
165
+
166
+ def get_path_parser() -> PathParser:
167
+ """Get the global path parser instance."""
168
+ global _path_parser
169
+ if _path_parser is None:
170
+ _path_parser = PathParser()
171
+ return _path_parser
172
+
173
+ def get_global_path_cache() -> GlobalPathCache:
174
+ """Get the global path cache instance."""
175
+ global _global_path_cache
176
+ if _global_path_cache is None:
177
+ _global_path_cache = GlobalPathCache()
178
+ return _global_path_cache
179
+
180
+
181
+ class XWNodeBase(iNodeFacade):
182
+ """
183
+ Abstract base class for all XWNode implementations.
184
+
185
+ This class provides the core functionality that all XWNode implementations
186
+ must have, working through the iNodeStrategy interface.
187
+ """
188
+
189
+ __slots__ = ('_strategy', '_hash_cache', '_type_cache')
190
+
191
+ def __init__(self, strategy: iNodeStrategy):
192
+ """Initialize with a strategy implementation."""
193
+ self._strategy = strategy
194
+ self._hash_cache = None
195
+ self._type_cache = None
196
+
197
+ @classmethod
198
+ def from_native(cls, data: Any) -> 'XWNodeBase':
199
+ """Create XWNodeBase from native data."""
200
+ # For now, we'll use a simple hash map strategy
201
+ # In the full implementation, this would use the strategy manager
202
+ from .strategies.simple import SimpleNodeStrategy
203
+ strategy = SimpleNodeStrategy.create_from_data(data)
204
+ return cls(strategy)
205
+
206
+ def get(self, path: str, default: Any = None) -> Optional['XWNodeBase']:
207
+ """Get a node by path."""
208
+ try:
209
+ result_strategy = self._strategy.get(path, default)
210
+ if result_strategy is None:
211
+ return None
212
+ return XWNodeBase(result_strategy)
213
+ except Exception:
214
+ return None
215
+
216
+ def set(self, path: str, value: Any, in_place: bool = True) -> 'XWNodeBase':
217
+ """Set a value at path."""
218
+ new_strategy = self._strategy.put(path, value)
219
+ if in_place:
220
+ self._strategy = new_strategy
221
+ return self
222
+ else:
223
+ return XWNodeBase(new_strategy)
224
+
225
+ def delete(self, path: str, in_place: bool = True) -> 'XWNodeBase':
226
+ """Delete a node at path."""
227
+ success = self._strategy.delete(path)
228
+ return self
229
+
230
+ def exists(self, path: str) -> bool:
231
+ """Check if path exists."""
232
+ return self._strategy.exists(path)
233
+
234
+ def find(self, path: str, in_place: bool = False) -> Optional['XWNodeBase']:
235
+ """Find a node by path."""
236
+ return self.get(path)
237
+
238
+ def to_native(self) -> Any:
239
+ """Convert to native Python object."""
240
+ return self._strategy.to_native()
241
+
242
+ def copy(self) -> 'XWNodeBase':
243
+ """Create a deep copy."""
244
+ return XWNodeBase(self._strategy.create_from_data(self._strategy.to_native()))
245
+
246
+ def count(self, path: str = ".") -> int:
247
+ """Count nodes at path."""
248
+ if path == ".":
249
+ return len(self._strategy)
250
+ node = self.get(path)
251
+ return len(node._strategy) if node else 0
252
+
253
+ def flatten(self, separator: str = ".") -> Dict[str, Any]:
254
+ """Flatten to dictionary."""
255
+ result = {}
256
+
257
+ def _flatten(node_strategy, prefix=""):
258
+ if node_strategy.is_leaf:
259
+ result[prefix or "root"] = node_strategy.value
260
+ elif node_strategy.is_dict:
261
+ for key in node_strategy.keys():
262
+ child = node_strategy.get(key)
263
+ new_prefix = f"{prefix}{separator}{key}" if prefix else key
264
+ _flatten(child, new_prefix)
265
+ elif node_strategy.is_list:
266
+ for i in range(len(node_strategy)):
267
+ child = node_strategy.get(str(i))
268
+ new_prefix = f"{prefix}{separator}{i}" if prefix else str(i)
269
+ _flatten(child, new_prefix)
270
+
271
+ _flatten(self._strategy)
272
+ return result
273
+
274
+ def merge(self, other: 'XWNodeBase', strategy: str = "replace") -> 'XWNodeBase':
275
+ """Merge with another node."""
276
+ # Simple implementation - just replace
277
+ return XWNodeBase(self._strategy.create_from_data(other.to_native()))
278
+
279
+ def diff(self, other: 'XWNodeBase') -> Dict[str, Any]:
280
+ """Get differences with another node."""
281
+ return {"changed": True} # Simple implementation
282
+
283
+ def transform(self, transformer: callable) -> 'XWNodeBase':
284
+ """Transform using a function."""
285
+ transformed_data = transformer(self.to_native())
286
+ return XWNodeBase(self._strategy.create_from_data(transformed_data))
287
+
288
+ def select(self, *paths: str) -> Dict[str, 'XWNodeBase']:
289
+ """Select multiple paths."""
290
+ result = {}
291
+ for path in paths:
292
+ node = self.get(path)
293
+ if node:
294
+ result[path] = node
295
+ return result
296
+
297
+ # Container methods
298
+ def __len__(self) -> int:
299
+ """Get length."""
300
+ return len(self._strategy)
301
+
302
+ def __iter__(self) -> Iterator['XWNodeBase']:
303
+ """Iterate over children."""
304
+ for child_strategy in self._strategy:
305
+ yield XWNodeBase(child_strategy)
306
+
307
+ def __getitem__(self, key: Union[str, int]) -> 'XWNodeBase':
308
+ """Get child by key or index."""
309
+ child_strategy = self._strategy[key]
310
+ return XWNodeBase(child_strategy)
311
+
312
+ def __setitem__(self, key: Union[str, int], value: Any) -> None:
313
+ """Set child by key or index."""
314
+ self._strategy[key] = value
315
+
316
+ def __contains__(self, key: Union[str, int]) -> bool:
317
+ """Check if key exists."""
318
+ return key in self._strategy
319
+
320
+ # Type checking properties
321
+ @property
322
+ def is_leaf(self) -> bool:
323
+ """Check if this is a leaf node."""
324
+ return self._strategy.is_leaf
325
+
326
+ @property
327
+ def is_list(self) -> bool:
328
+ """Check if this is a list node."""
329
+ return self._strategy.is_list
330
+
331
+ @property
332
+ def is_dict(self) -> bool:
333
+ """Check if this is a dict node."""
334
+ return self._strategy.is_dict
335
+
336
+ @property
337
+ def type(self) -> str:
338
+ """Get the type of this node."""
339
+ return self._strategy.type
340
+
341
+ @property
342
+ def value(self) -> Any:
343
+ """Get the value of this node."""
344
+ return self._strategy.value
345
+
346
+
347
+ class aEdge(iEdge):
348
+ """Abstract base class for edge implementations."""
349
+
350
+ def __init__(self, strategy: iEdgeStrategy):
351
+ self._strategy = strategy
352
+
353
+ def add_edge(self, source: str, target: str, edge_type: str = "default",
354
+ weight: float = 1.0, properties: Optional[Dict[str, Any]] = None,
355
+ is_bidirectional: bool = False, edge_id: Optional[str] = None) -> str:
356
+ """Add an edge between source and target with advanced properties."""
357
+ return self._strategy.add_edge(source, target, edge_type, weight, properties, is_bidirectional, edge_id)
358
+
359
+ def remove_edge(self, source: str, target: str, edge_id: Optional[str] = None) -> bool:
360
+ """Remove an edge between source and target."""
361
+ return self._strategy.remove_edge(source, target, edge_id)
362
+
363
+ def has_edge(self, source: str, target: str) -> bool:
364
+ """Check if edge exists between source and target."""
365
+ return self._strategy.has_edge(source, target)
366
+
367
+ def get_neighbors(self, node: str, edge_type: Optional[str] = None, direction: str = "outgoing") -> List[str]:
368
+ """Get neighbors of a node with optional filtering."""
369
+ return self._strategy.get_neighbors(node, edge_type, direction)
370
+
371
+ def get_edges(self, edge_type: Optional[str] = None, direction: str = "both") -> List[Dict[str, Any]]:
372
+ """Get all edges with metadata."""
373
+ return self._strategy.get_edges(edge_type, direction)
374
+
375
+ def get_edge_data(self, source: str, target: str, edge_id: Optional[str] = None) -> Optional[Dict[str, Any]]:
376
+ """Get edge data/properties."""
377
+ return self._strategy.get_edge_data(source, target, edge_id)
378
+
379
+ def shortest_path(self, source: str, target: str, edge_type: Optional[str] = None) -> List[str]:
380
+ """Find shortest path between nodes."""
381
+ return self._strategy.shortest_path(source, target, edge_type)
382
+
383
+ def find_cycles(self, start_node: str, edge_type: Optional[str] = None, max_depth: int = 10) -> List[List[str]]:
384
+ """Find cycles in the graph."""
385
+ return self._strategy.find_cycles(start_node, edge_type, max_depth)
386
+
387
+ def traverse_graph(self, start_node: str, strategy: str = "bfs", max_depth: int = 100,
388
+ edge_type: Optional[str] = None) -> Iterator[str]:
389
+ """Traverse the graph with cycle detection."""
390
+ return self._strategy.traverse_graph(start_node, strategy, max_depth, edge_type)
391
+
392
+ def is_connected(self, source: str, target: str, edge_type: Optional[str] = None) -> bool:
393
+ """Check if nodes are connected."""
394
+ return self._strategy.is_connected(source, target, edge_type)
395
+
396
+ def __len__(self) -> int:
397
+ """Get number of edges."""
398
+ return len(self._strategy)
399
+
400
+ def __iter__(self) -> Iterator[Dict[str, Any]]:
401
+ """Iterate over edges with full metadata."""
402
+ return iter(self._strategy)
403
+
404
+ def to_native(self) -> Any:
405
+ """Convert to native Python object."""
406
+ return self._strategy.to_native()
407
+
408
+ def copy(self) -> 'aEdge':
409
+ """Create a deep copy."""
410
+ return aEdge(copy.deepcopy(self._strategy))
411
+
412
+
413
+ class aQuery(iQuery):
414
+ """Abstract base class for query implementations."""
415
+
416
+ def __init__(self, node: XWNodeBase, engine: iQueryEngine):
417
+ self._node = node
418
+ self._engine = engine
419
+
420
+ def query(self, query_string: str, query_type: str = "hybrid", **kwargs) -> iQueryResult:
421
+ """Execute a query."""
422
+ context = {"node": self._node, "type": query_type, **kwargs}
423
+ return self._engine.execute_query(query_string, context)
424
+
425
+ def find_nodes(self, predicate: Callable[[XWNodeBase], bool], max_results: Optional[int] = None) -> iQueryResult:
426
+ """Find nodes matching predicate."""
427
+ # Simple implementation
428
+ results = []
429
+ count = 0
430
+
431
+ def _search(node):
432
+ nonlocal count
433
+ if max_results and count >= max_results:
434
+ return
435
+ if predicate(node):
436
+ results.append(node)
437
+ count += 1
438
+
439
+ for child in node:
440
+ _search(child)
441
+
442
+ _search(self._node)
443
+ return SimpleQueryResult(results)
444
+
445
+ def find_by_path(self, path_pattern: str) -> iQueryResult:
446
+ """Find nodes by path pattern."""
447
+ # Simple implementation - exact match
448
+ node = self._node.get(path_pattern)
449
+ return SimpleQueryResult([node] if node else [])
450
+
451
+ def find_by_value(self, value: Any, exact_match: bool = True) -> iQueryResult:
452
+ """Find nodes by value."""
453
+ results = []
454
+
455
+ def _search(node):
456
+ if exact_match:
457
+ if node.value == value:
458
+ results.append(node)
459
+ else:
460
+ if str(value) in str(node.value):
461
+ results.append(node)
462
+
463
+ for child in node:
464
+ _search(child)
465
+
466
+ _search(self._node)
467
+ return SimpleQueryResult(results)
468
+
469
+ def count_nodes(self, predicate: Optional[Callable[[XWNodeBase], bool]] = None) -> int:
470
+ """Count nodes matching predicate."""
471
+ if predicate is None:
472
+ return self._node.count()
473
+
474
+ count = 0
475
+ def _count(node):
476
+ nonlocal count
477
+ if predicate(node):
478
+ count += 1
479
+ for child in node:
480
+ _count(child)
481
+
482
+ _count(self._node)
483
+ return count
484
+
485
+ # Simplified implementations for other methods
486
+ def select(self, selector: str, **kwargs) -> List[XWNodeBase]:
487
+ return []
488
+
489
+ def filter(self, condition: str, **kwargs) -> List[XWNodeBase]:
490
+ return []
491
+
492
+ def where(self, condition: str) -> List[XWNodeBase]:
493
+ return []
494
+
495
+ def sort(self, key: str = None, reverse: bool = False) -> List[XWNodeBase]:
496
+ return []
497
+
498
+ def limit(self, count: int) -> List[XWNodeBase]:
499
+ return []
500
+
501
+ def skip(self, count: int) -> List[XWNodeBase]:
502
+ return []
503
+
504
+ def first(self) -> Optional[XWNodeBase]:
505
+ return None
506
+
507
+ def last(self) -> Optional[XWNodeBase]:
508
+ return None
509
+
510
+ def group_by(self, key: str) -> Dict[str, List[XWNodeBase]]:
511
+ return {}
512
+
513
+ def distinct(self, key: str = None) -> List[XWNodeBase]:
514
+ return []
515
+
516
+ def clear_query_cache(self):
517
+ pass
518
+
519
+ def get_query_stats(self) -> Dict[str, Any]:
520
+ return {}
521
+
522
+
523
+ class SimpleQueryResult(iQueryResult):
524
+ """Simple implementation of query results."""
525
+
526
+ def __init__(self, nodes: List[XWNodeBase]):
527
+ self._nodes = nodes
528
+ self._metadata = {}
529
+
530
+ @property
531
+ def nodes(self) -> List[XWNodeBase]:
532
+ return self._nodes
533
+
534
+ @property
535
+ def metadata(self) -> Dict[str, Any]:
536
+ return self._metadata
537
+
538
+ def first(self) -> Optional[XWNodeBase]:
539
+ return self._nodes[0] if self._nodes else None
540
+
541
+ def count(self) -> int:
542
+ return len(self._nodes)
543
+
544
+ def filter(self, predicate: Callable[[XWNodeBase], bool]) -> 'SimpleQueryResult':
545
+ filtered = [node for node in self._nodes if predicate(node)]
546
+ return SimpleQueryResult(filtered)
547
+
548
+ def limit(self, limit: int) -> 'SimpleQueryResult':
549
+ return SimpleQueryResult(self._nodes[:limit])
550
+
551
+ def offset(self, offset: int) -> 'SimpleQueryResult':
552
+ return SimpleQueryResult(self._nodes[offset:])
553
+
554
+
555
+ class aQueryResult(iQueryResult):
556
+ """Abstract base class for query results."""
557
+ pass
558
+
559
+
560
+ class aQueryEngine(iQueryEngine):
561
+ """Abstract base class for query engines with multi-language support."""
562
+
563
+ def __init__(self):
564
+ self._parsers = {}
565
+ self._register_default_parsers()
566
+
567
+ def _register_default_parsers(self):
568
+ """Register default query language parsers."""
569
+ # JSONPath-style queries
570
+ self._parsers['jsonpath'] = self._parse_jsonpath
571
+ self._parsers['xpath'] = self._parse_xpath
572
+ self._parsers['css'] = self._parse_css_selector
573
+ self._parsers['jq'] = self._parse_jq
574
+ self._parsers['sql'] = self._parse_sql_like
575
+ self._parsers['mongo'] = self._parse_mongodb
576
+ self._parsers['graphql'] = self._parse_graphql
577
+ # Default hybrid parser
578
+ self._parsers['hybrid'] = self._parse_hybrid
579
+
580
+ def register_parser(self, language: str, parser_func: Callable):
581
+ """Register a custom query language parser."""
582
+ self._parsers[language] = parser_func
583
+
584
+ def detect_query_language(self, query_string: str) -> str:
585
+ """Auto-detect query language from query string."""
586
+ query = query_string.strip()
587
+
588
+ # GraphQL detection
589
+ if query.startswith('{') and ('query' in query or 'mutation' in query):
590
+ return 'graphql'
591
+
592
+ # SQL-like detection
593
+ if any(keyword in query.upper() for keyword in ['SELECT', 'FROM', 'WHERE', 'JOIN']):
594
+ return 'sql'
595
+
596
+ # MongoDB detection
597
+ if query.startswith('{') and any(op in query for op in ['$match', '$group', '$sort', '$project']):
598
+ return 'mongo'
599
+
600
+ # XPath detection
601
+ if query.startswith('/') or query.startswith('//') or '//' in query:
602
+ return 'xpath'
603
+
604
+ # CSS selector detection
605
+ if any(sel in query for sel in ['.', '#', '[', ':', '>']):
606
+ return 'css'
607
+
608
+ # jq detection
609
+ if query.startswith('.') or any(func in query for func in ['map', 'select', 'group_by']):
610
+ return 'jq'
611
+
612
+ # JSONPath detection
613
+ if query.startswith('$') or '..' in query:
614
+ return 'jsonpath'
615
+
616
+ # Default to hybrid
617
+ return 'hybrid'
618
+
619
+ @measure_operation('query_execute')
620
+ def execute_query(self, query_string: str, context: Dict[str, Any]) -> iQueryResult:
621
+ """Execute query with auto-detection or explicit language."""
622
+ query_type = context.get('query_type', self.detect_query_language(query_string))
623
+
624
+ if query_type not in self._parsers:
625
+ logger.warning(f"Unknown query language: {query_type}, falling back to hybrid")
626
+ query_type = 'hybrid'
627
+
628
+ try:
629
+ return self._parsers[query_type](query_string, context)
630
+ except Exception as e:
631
+ logger.error(f"Query execution failed for {query_type}: {e}")
632
+ # Fallback to hybrid parser
633
+ if query_type != 'hybrid':
634
+ return self._parsers['hybrid'](query_string, context)
635
+ raise
636
+
637
+ def _parse_jsonpath(self, query: str, context: Dict[str, Any]) -> iQueryResult:
638
+ """Parse JSONPath-style queries."""
639
+ # Implementation would use jsonpath library
640
+ logger.debug(f"Parsing JSONPath query: {query}")
641
+ return SimpleQueryResult([])
642
+
643
+ def _parse_xpath(self, query: str, context: Dict[str, Any]) -> iQueryResult:
644
+ """Parse XPath-style queries."""
645
+ logger.debug(f"Parsing XPath query: {query}")
646
+ return SimpleQueryResult([])
647
+
648
+ def _parse_css_selector(self, query: str, context: Dict[str, Any]) -> iQueryResult:
649
+ """Parse CSS selector-style queries."""
650
+ logger.debug(f"Parsing CSS selector query: {query}")
651
+ return SimpleQueryResult([])
652
+
653
+ def _parse_jq(self, query: str, context: Dict[str, Any]) -> iQueryResult:
654
+ """Parse jq-style queries."""
655
+ logger.debug(f"Parsing jq query: {query}")
656
+ return SimpleQueryResult([])
657
+
658
+ def _parse_sql_like(self, query: str, context: Dict[str, Any]) -> iQueryResult:
659
+ """Parse SQL-like queries."""
660
+ logger.debug(f"Parsing SQL-like query: {query}")
661
+ return SimpleQueryResult([])
662
+
663
+ def _parse_mongodb(self, query: str, context: Dict[str, Any]) -> iQueryResult:
664
+ """Parse MongoDB-style queries."""
665
+ logger.debug(f"Parsing MongoDB query: {query}")
666
+ return SimpleQueryResult([])
667
+
668
+ def _parse_graphql(self, query: str, context: Dict[str, Any]) -> iQueryResult:
669
+ """Parse GraphQL-style queries."""
670
+ logger.debug(f"Parsing GraphQL query: {query}")
671
+ return SimpleQueryResult([])
672
+
673
+ def _parse_hybrid(self, query: str, context: Dict[str, Any]) -> iQueryResult:
674
+ """Parse hybrid/default queries."""
675
+ logger.debug(f"Parsing hybrid query: {query}")
676
+ return SimpleQueryResult([])