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,1434 @@
1
+ """
2
+ #exonware/xwnode/src/exonware/xwnode/strategies/nodes/node_tree_graph_hybrid.py
3
+
4
+ Tree Graph Hybrid Strategy Implementation
5
+
6
+ This module provides a unified tree engine strategy that contains all the XWNodeBase functionality
7
+ in one file, decoupled from XWNode. This eliminates the dual architecture and provides
8
+ a single, clean implementation.
9
+ """
10
+
11
+ import threading
12
+ import copy
13
+ from abc import ABC, abstractmethod
14
+ from typing import Any, Union, List, Dict, Optional, Iterator, Tuple, Callable
15
+ from collections import OrderedDict
16
+
17
+ from ...types import NodeMode, NodeTrait
18
+ from ...abc import iNodeStrategy, NodeTrait
19
+ from ...errors import xNodePathError
20
+ from exonware.xwsystem import get_logger
21
+
22
+ logger = get_logger(__name__)
23
+
24
+ # Import shared utilities
25
+ from ..utils import (
26
+ PathParser, TrieNode, UnionFind, MinHeap,
27
+ create_path_parser, create_performance_tracker
28
+ )
29
+
30
+ logger = get_logger('xnode.tree_engine')
31
+
32
+ # ============================================================================
33
+ # TREE GRAPH HYBRID INTERNAL NODE CLASSES
34
+ # ============================================================================
35
+
36
+ class TreeGraphNode(ABC):
37
+ """Abstract base for all internal nodes in the TreeGraphHybrid strategy."""
38
+ __slots__ = ('_parent', '_cached_native', '_hash')
39
+
40
+ def __init__(self, parent: Optional['TreeGraphNode'] = None):
41
+ self._parent: Optional['TreeGraphNode'] = parent
42
+ self._cached_native: Optional[Any] = None
43
+ self._hash: Optional[int] = None
44
+
45
+ @property
46
+ def parent(self) -> Optional['TreeGraphNode']:
47
+ """Get the parent node."""
48
+ return self._parent
49
+
50
+ @parent.setter
51
+ def parent(self, value: Optional['TreeGraphNode']):
52
+ """Set the parent node."""
53
+ self._parent = value
54
+
55
+ def _get_child(self, key_or_index: Union[str, int]) -> 'TreeGraphNode':
56
+ """Get a child node by key or index."""
57
+ raise TypeError(f"Node type {type(self).__name__} does not support child access.")
58
+
59
+ @abstractmethod
60
+ def _to_native(self) -> Any:
61
+ """Convert this node and its children to a native Python object."""
62
+ pass
63
+
64
+ def _invalidate_cache(self):
65
+ """Invalidate cached data when the node changes."""
66
+ self._cached_native = None
67
+ self._hash = None
68
+ # Propagate invalidation up the tree
69
+ if self._parent:
70
+ self._parent._invalidate_cache()
71
+
72
+ def _get_root(self) -> 'TreeGraphNode':
73
+ """Get the root node of the tree."""
74
+ current = self
75
+ while current._parent is not None:
76
+ current = current._parent
77
+ return current
78
+
79
+ def _get_key_in_parent(self) -> Optional[Union[str, int]]:
80
+ """Get the key or index of this node in its parent."""
81
+ if self._parent is None:
82
+ return None
83
+
84
+ if isinstance(self._parent, TreeGraphDictNode):
85
+ for key, child in self._parent._children.items():
86
+ if child is self:
87
+ return key
88
+ elif isinstance(self._parent, TreeGraphListNode):
89
+ try:
90
+ return self._parent._children.index(self)
91
+ except ValueError:
92
+ pass
93
+
94
+ return None
95
+
96
+ def _get_path(self) -> str:
97
+ """Get the path from the root to this node as a dot-separated string."""
98
+ if self._parent is None:
99
+ return ""
100
+
101
+ parent_path = self._parent._get_path()
102
+ key = self._get_key_in_parent()
103
+
104
+ if key is None:
105
+ return parent_path
106
+
107
+ if parent_path:
108
+ return f"{parent_path}.{key}"
109
+ else:
110
+ return str(key)
111
+
112
+ def cleanup(self) -> None:
113
+ """Clean up the node before returning to pool."""
114
+ self._parent = None
115
+ self._cached_native = None
116
+ self._hash = None
117
+
118
+ def reset(self, parent: Optional['TreeGraphNode'] = None) -> None:
119
+ """Reset the node to initial state."""
120
+ self._parent = parent
121
+ self._cached_native = None
122
+ self._hash = None
123
+
124
+
125
+ class TreeGraphValueNode(TreeGraphNode):
126
+ """Internal node for a primitive value in TreeGraphHybrid strategy."""
127
+ __slots__ = ('_value',)
128
+
129
+ def __init__(self, value: Any, parent: Optional['TreeGraphNode'] = None):
130
+ super().__init__(parent)
131
+ self._value = value
132
+
133
+ @property
134
+ def value(self) -> Any:
135
+ """Get the primitive value stored in this leaf node."""
136
+ return self._value
137
+
138
+ def _to_native(self) -> Any:
139
+ """Convert this node to a native Python object."""
140
+ return self._value
141
+
142
+
143
+ class TreeGraphListNode(TreeGraphNode):
144
+ """Internal node for a list with lazy-loading in TreeGraphHybrid strategy."""
145
+ __slots__ = ('_children', '_source_data', '_is_lazy')
146
+
147
+ def __init__(self, source_data: List[Any], is_lazy: bool, parent: Optional['TreeGraphNode'] = None):
148
+ super().__init__(parent)
149
+ self._source_data = source_data
150
+ self._is_lazy = is_lazy
151
+ self._children: List['TreeGraphNode'] = []
152
+
153
+ # Don't load children here to avoid recursion
154
+ # They will be loaded on-demand in _get_child, _to_native, etc.
155
+
156
+ def _eager_load(self, data: List[Any]) -> List['TreeGraphNode']:
157
+ """Eagerly load all children."""
158
+ self._children = []
159
+ for item in data:
160
+ if item is None:
161
+ self._children.append(TreeGraphValueNode(None, self))
162
+ elif isinstance(item, (str, int, float, bool)):
163
+ self._children.append(TreeGraphValueNode(item, self))
164
+ elif isinstance(item, list):
165
+ is_lazy = len(item) > 100
166
+ self._children.append(TreeGraphListNode(item, is_lazy, self))
167
+ elif isinstance(item, dict):
168
+ is_lazy = len(item) > 100
169
+ self._children.append(TreeGraphDictNode(item, is_lazy, self))
170
+ else:
171
+ self._children.append(TreeGraphValueNode(item, self))
172
+
173
+ self._source_data = None # Clear source data after loading
174
+ return self._children
175
+
176
+ def _get_child(self, index: Union[str, int]) -> 'TreeGraphNode':
177
+ """Get a child node by index."""
178
+ if isinstance(index, str):
179
+ try:
180
+ index = int(index)
181
+ except ValueError:
182
+ raise TypeError(f"List index must be an integer, got {index}")
183
+
184
+ if not isinstance(index, int):
185
+ raise TypeError(f"List index must be an integer, got {type(index).__name__}")
186
+
187
+ if index < 0:
188
+ index = len(self) + index
189
+
190
+ if index < 0 or index >= len(self):
191
+ raise IndexError(f"List index {index} out of range")
192
+
193
+ # Lazy load if needed
194
+ if self._source_data is not None:
195
+ self._eager_load(self._source_data)
196
+
197
+ return self._children[index]
198
+
199
+ def _to_native(self) -> List[Any]:
200
+ """Convert this node and its children to a native Python object."""
201
+ # Lazy load if needed
202
+ if self._source_data is not None:
203
+ self._eager_load(self._source_data)
204
+
205
+ return [child._to_native() for child in self._children]
206
+
207
+ def __iter__(self) -> Iterator['TreeGraphNode']:
208
+ """Iterate over child nodes."""
209
+ if self._source_data is not None:
210
+ self._eager_load(self._source_data)
211
+ return iter(self._children)
212
+
213
+ def __len__(self) -> int:
214
+ """Get the number of child nodes."""
215
+ if self._source_data is not None:
216
+ return len(self._source_data)
217
+ return len(self._children)
218
+
219
+
220
+ class TreeGraphDictNode(TreeGraphNode):
221
+ """Internal node for a dictionary with lazy-loading in TreeGraphHybrid strategy."""
222
+ __slots__ = ('_children', '_source_data', '_is_lazy', '_keys')
223
+
224
+ def __init__(self, source_data: Dict[str, Any], is_lazy: bool, parent: Optional['TreeGraphNode'] = None):
225
+ super().__init__(parent)
226
+ self._source_data = source_data
227
+ self._is_lazy = is_lazy
228
+ self._children: Dict[str, 'TreeGraphNode'] = {}
229
+ self._keys = list(source_data.keys())
230
+
231
+ # Don't load children here to avoid recursion
232
+ # They will be loaded on-demand in _get_child, _to_native, etc.
233
+
234
+ def _eager_load(self, data: Dict[str, Any]) -> Dict[str, 'TreeGraphNode']:
235
+ """Eagerly load all children."""
236
+ # Don't clear existing children if we're loading from empty data
237
+ if not data:
238
+ self._source_data = None
239
+ return self._children
240
+
241
+ self._children = {}
242
+ for key, value in data.items():
243
+ if value is None:
244
+ self._children[key] = TreeGraphValueNode(None, self)
245
+ elif isinstance(value, (str, int, float, bool)):
246
+ self._children[key] = TreeGraphValueNode(value, self)
247
+ elif isinstance(value, list):
248
+ is_lazy = len(value) > 100
249
+ self._children[key] = TreeGraphListNode(value, is_lazy, self)
250
+ elif isinstance(value, dict):
251
+ is_lazy = len(value) > 100
252
+ self._children[key] = TreeGraphDictNode(value, is_lazy, self)
253
+ else:
254
+ self._children[key] = TreeGraphValueNode(value, self)
255
+
256
+ self._source_data = None # Clear source data after loading
257
+ return self._children
258
+
259
+ def _get_child(self, key: Union[str, int]) -> 'TreeGraphNode':
260
+ """Get a child node by key."""
261
+ if not isinstance(key, str):
262
+ raise TypeError(f"Dictionary key must be a string, got {type(key).__name__}")
263
+
264
+ # Lazy load if needed
265
+ if self._source_data is not None:
266
+ self._eager_load(self._source_data)
267
+
268
+ # Check if key exists in children
269
+ if key not in self._children:
270
+ raise xNodePathError(f"Key '{key}' not found in dictionary")
271
+
272
+ return self._children[key]
273
+
274
+ def _to_native(self) -> Dict[str, Any]:
275
+ """Convert this node and its children to a native Python object."""
276
+ # Lazy load if needed
277
+ if self._source_data is not None:
278
+ self._eager_load(self._source_data)
279
+
280
+ return {key: child._to_native() for key, child in self._children.items()}
281
+
282
+ def items(self) -> Iterator[Tuple[str, 'TreeGraphNode']]:
283
+ """Iterate over key-value pairs."""
284
+ if self._source_data is not None:
285
+ self._eager_load(self._source_data)
286
+ return self._children.items()
287
+
288
+ def __iter__(self) -> Iterator['TreeGraphNode']:
289
+ """Iterate over child nodes."""
290
+ if self._source_data is not None:
291
+ self._eager_load(self._source_data)
292
+ return iter(self._children.values())
293
+
294
+ def __len__(self) -> int:
295
+ """Get the number of child nodes."""
296
+ if self._source_data is not None:
297
+ return len(self._source_data)
298
+ return len(self._children)
299
+
300
+ def keys(self) -> Iterator[str]:
301
+ """Iterate over keys."""
302
+ if self._source_data is not None:
303
+ return iter(self._source_data.keys())
304
+ return iter(self._children.keys())
305
+
306
+
307
+ class TreeGraphReferenceNode(TreeGraphNode):
308
+ """Internal node for a reference in TreeGraphHybrid strategy."""
309
+ __slots__ = ('_uri', '_reference_type', '_metadata')
310
+
311
+ def __init__(self, uri: str, reference_type: str, metadata: Dict[str, Any], parent: Optional['TreeGraphNode'] = None):
312
+ super().__init__(parent)
313
+ self._uri = uri
314
+ self._reference_type = reference_type
315
+ self._metadata = metadata or {}
316
+
317
+ @property
318
+ def uri(self) -> str:
319
+ """Get the URI of the reference."""
320
+ return self._uri
321
+
322
+ @property
323
+ def reference_type(self) -> str:
324
+ """Get the type of the reference."""
325
+ return self._reference_type
326
+
327
+ @property
328
+ def metadata(self) -> Dict[str, Any]:
329
+ """Get the metadata of the reference."""
330
+ return self._metadata
331
+
332
+ def _to_native(self) -> Dict[str, Any]:
333
+ """Convert this node to a native Python object."""
334
+ return {
335
+ 'type': 'reference',
336
+ 'uri': self._uri,
337
+ 'reference_type': self._reference_type,
338
+ 'metadata': self._metadata
339
+ }
340
+
341
+ def cleanup(self) -> None:
342
+ """Clean up the node before returning to pool."""
343
+ super().cleanup()
344
+ self._uri = ""
345
+ self._reference_type = ""
346
+ self._metadata = {}
347
+
348
+ def reset(self, uri: str, reference_type: str, metadata: Dict[str, Any], parent: Optional['TreeGraphNode'] = None) -> None:
349
+ """Reset the node to initial state."""
350
+ super().reset(parent)
351
+ self._uri = uri
352
+ self._reference_type = reference_type
353
+ self._metadata = metadata or {}
354
+
355
+
356
+ class TreeGraphObjectNode(TreeGraphNode):
357
+ """Internal node for an object reference in TreeGraphHybrid strategy."""
358
+ __slots__ = ('_uri', '_object_type', '_mime_type', '_size', '_metadata')
359
+
360
+ def __init__(self, uri: str, object_type: str, mime_type: Optional[str], size: Optional[int], metadata: Dict[str, Any], parent: Optional['TreeGraphNode'] = None):
361
+ super().__init__(parent)
362
+ self._uri = uri
363
+ self._object_type = object_type
364
+ self._mime_type = mime_type
365
+ self._size = size
366
+ self._metadata = metadata or {}
367
+
368
+ @property
369
+ def uri(self) -> str:
370
+ """Get the URI of the object."""
371
+ return self._uri
372
+
373
+ @property
374
+ def object_type(self) -> str:
375
+ """Get the type of the object."""
376
+ return self._object_type
377
+
378
+ @property
379
+ def mime_type(self) -> Optional[str]:
380
+ """Get the MIME type of the object."""
381
+ return self._mime_type
382
+
383
+ @property
384
+ def size(self) -> Optional[int]:
385
+ """Get the size of the object."""
386
+ return self._size
387
+
388
+ @property
389
+ def metadata(self) -> Dict[str, Any]:
390
+ """Get the metadata of the object."""
391
+ return self._metadata
392
+
393
+ def _to_native(self) -> Dict[str, Any]:
394
+ """Convert this node to a native Python object."""
395
+ result = {
396
+ 'type': 'object',
397
+ 'uri': self._uri,
398
+ 'object_type': self._object_type,
399
+ 'metadata': self._metadata
400
+ }
401
+ if self._mime_type:
402
+ result['mime_type'] = self._mime_type
403
+ if self._size is not None:
404
+ result['size'] = self._size
405
+ return result
406
+
407
+ def cleanup(self) -> None:
408
+ """Clean up the node before returning to pool."""
409
+ super().cleanup()
410
+ self._uri = ""
411
+ self._object_type = ""
412
+ self._mime_type = None
413
+ self._size = None
414
+ self._metadata = {}
415
+
416
+ def reset(self, uri: str, object_type: str, mime_type: Optional[str], size: Optional[int], metadata: Dict[str, Any], parent: Optional['TreeGraphNode'] = None) -> None:
417
+ """Reset the node to initial state."""
418
+ super().reset(parent)
419
+ self._uri = uri
420
+ self._object_type = object_type
421
+ self._mime_type = mime_type
422
+ self._size = size
423
+ self._metadata = metadata or {}
424
+
425
+
426
+ # ============================================================================
427
+ # TREE GRAPH HYBRID NODE FACTORY
428
+ # ============================================================================
429
+
430
+ class TreeGraphNodeFactory:
431
+ """Factory for creating TreeGraphHybrid internal nodes with performance optimizations."""
432
+
433
+ @staticmethod
434
+ def from_native(data: Any, parent: Optional[TreeGraphNode] = None, depth: int = 0, visited: Optional[set] = None) -> TreeGraphNode:
435
+ """Create a node from native Python data."""
436
+ # Check depth limit
437
+ if depth > 1000: # Simple depth limit
438
+ raise ValueError("Maximum depth exceeded")
439
+
440
+ # Initialize visited set for circular reference detection
441
+ if visited is None:
442
+ visited = set()
443
+
444
+ # Check for circular references
445
+ if id(data) in visited:
446
+ # Return a placeholder node for circular references
447
+ return TreeGraphValueNode(f"<circular_reference_{id(data)}>", parent)
448
+
449
+ # Add current object to visited set
450
+ visited.add(id(data))
451
+
452
+ try:
453
+ if data is None:
454
+ node = TreeGraphValueNode(None, parent)
455
+ elif isinstance(data, (str, int, float, bool)):
456
+ node = TreeGraphValueNode(data, parent)
457
+ elif isinstance(data, list):
458
+ # Determine if lazy loading should be used
459
+ is_lazy = len(data) > 100
460
+ node = TreeGraphListNode(data, is_lazy, parent)
461
+ elif isinstance(data, dict):
462
+ # Determine if lazy loading should be used
463
+ is_lazy = len(data) > 100
464
+ node = TreeGraphDictNode(data, is_lazy, parent)
465
+ else:
466
+ # For other types, create a value node
467
+ node = TreeGraphValueNode(data, parent)
468
+
469
+ return node
470
+ finally:
471
+ # Remove current object from visited set when done
472
+ visited.discard(id(data))
473
+
474
+ @staticmethod
475
+ def to_native(node: TreeGraphNode) -> Any:
476
+ """Convert a node to native Python data."""
477
+ return node._to_native()
478
+
479
+
480
+ # ============================================================================
481
+ # PATH PARSER (Moved from core.py)
482
+ # ============================================================================
483
+
484
+ class PathParser:
485
+ """Thread-safe path parser with caching."""
486
+
487
+ def __init__(self, max_cache_size: int = 1024):
488
+ self._cache = OrderedDict()
489
+ self._max_cache_size = max_cache_size
490
+ self._lock = threading.RLock()
491
+
492
+ def parse(self, path: str) -> List[str]:
493
+ """Parse a path string into parts."""
494
+ with self._lock:
495
+ if path in self._cache:
496
+ return self._cache[path]
497
+
498
+ parts = self._parse_path(path)
499
+
500
+ # Cache the result
501
+ if len(self._cache) >= self._max_cache_size:
502
+ self._cache.popitem(last=False)
503
+ self._cache[path] = parts
504
+
505
+ return parts
506
+
507
+ def _parse_path(self, path: str) -> List[str]:
508
+ """Internal path parsing logic."""
509
+ if not path:
510
+ return []
511
+
512
+ # Simple dot-separated path parsing
513
+ return [part for part in path.split('.') if part]
514
+
515
+
516
+ # ============================================================================
517
+ # TREE GRAPH HYBRID STRATEGY
518
+ # ============================================================================
519
+
520
+ class TreeGraphHybridStrategy(iNodeStrategy):
521
+ """
522
+ Unified TreeGraphHybrid strategy combining aNode model with advanced data structures.
523
+
524
+ This strategy provides:
525
+ - Tree-based navigation with graph capabilities
526
+ - Advanced data structures (Trie, Heap, Union-Find, etc.)
527
+ - Performance optimizations and caching
528
+ - Circular reference detection
529
+ - Lazy loading and object pooling
530
+ """
531
+
532
+ def __init__(self):
533
+ """Initialize the TreeGraphHybrid strategy."""
534
+ self._root: Optional[TreeGraphNode] = None
535
+ self._node_count = 0
536
+ self._edge_count = 0
537
+ self._cache = {}
538
+ self._size = 0
539
+ self._performance_stats = {
540
+ 'cache_hits': 0,
541
+ 'cache_misses': 0,
542
+ 'operations': 0
543
+ }
544
+ # Initialize shared utilities
545
+ self._path_parser = create_path_parser()
546
+ self._performance_tracker = create_performance_tracker()
547
+
548
+ @property
549
+ def strategy_name(self) -> str:
550
+ """Get the name of this strategy."""
551
+ return "tree_graph_hybrid"
552
+
553
+ @property
554
+ def supported_traits(self) -> List[NodeTrait]:
555
+ """Get supported traits for this strategy."""
556
+ return [
557
+ NodeTrait.LAZY_LOADING,
558
+ NodeTrait.OBJECT_POOLING,
559
+ NodeTrait.CIRCULAR_REF_DETECTION,
560
+ NodeTrait.PERFORMANCE_TRACKING,
561
+ NodeTrait.GRAPH_CAPABILITIES,
562
+ NodeTrait.QUERY_CAPABILITIES,
563
+ NodeTrait.SECURITY_FEATURES
564
+ ]
565
+
566
+ def create_from_data(self, data: Any) -> 'TreeGraphHybridStrategy':
567
+ """Create the tree from data."""
568
+ self._root = TreeGraphNodeFactory.from_native(data)
569
+ self._size = self._calculate_size(self._root)
570
+ # Force eager loading for immediate access
571
+ if isinstance(self._root, TreeGraphDictNode) and self._root._source_data is not None:
572
+ self._root._eager_load(self._root._source_data)
573
+ elif isinstance(self._root, TreeGraphListNode) and self._root._source_data is not None:
574
+ self._root._eager_load(self._root._source_data)
575
+ return self
576
+
577
+ def _calculate_size(self, node: TreeGraphNode) -> int:
578
+ """Calculate the size of the tree."""
579
+ if isinstance(node, TreeGraphValueNode):
580
+ return 1
581
+ elif isinstance(node, TreeGraphListNode):
582
+ # For lists, return the number of items
583
+ if node._source_data is not None:
584
+ return len(node._source_data)
585
+ else:
586
+ return len(node._children)
587
+ elif isinstance(node, TreeGraphDictNode):
588
+ # For dictionaries, return the number of key-value pairs
589
+ if node._source_data is not None:
590
+ return len(node._source_data)
591
+ else:
592
+ return len(node._children)
593
+ else:
594
+ return 1
595
+
596
+ def get_native(self, key: str, default: Any = None) -> Any:
597
+ """Get a native Python value by key."""
598
+ self._performance_tracker.record_access()
599
+
600
+ try:
601
+ if self._root is None:
602
+ return default
603
+
604
+ # Handle path navigation
605
+ if '.' in key:
606
+ return self._get_by_path(key, default)
607
+
608
+ # Handle direct key access
609
+ if isinstance(self._root, TreeGraphDictNode):
610
+ child = self._root._get_child(key)
611
+ return child._to_native()
612
+ elif isinstance(self._root, TreeGraphListNode):
613
+ try:
614
+ index = int(key)
615
+ child = self._root._get_child(index)
616
+ return child._to_native()
617
+ except ValueError:
618
+ return default
619
+ elif isinstance(self._root, TreeGraphValueNode):
620
+ # If root is a value node, only return it if key is empty or matches
621
+ if key == "" or key == "value":
622
+ return self._root._to_native()
623
+ return default
624
+ else:
625
+ return default
626
+
627
+ except (KeyError, IndexError, TypeError):
628
+ return default
629
+
630
+ def _get_by_path(self, path: str, default: Any = None) -> Any:
631
+ """Get a value by path."""
632
+ if self._root is None:
633
+ return default
634
+
635
+ try:
636
+ segments = self._path_parser.parse(path)
637
+ current = self._root
638
+
639
+ for segment in segments:
640
+ if isinstance(current, TreeGraphDictNode):
641
+ current = current._get_child(segment)
642
+ elif isinstance(current, TreeGraphListNode):
643
+ try:
644
+ index = int(segment)
645
+ current = current._get_child(index)
646
+ except ValueError:
647
+ return default
648
+ else:
649
+ return default
650
+
651
+ return current._to_native()
652
+
653
+ except (KeyError, IndexError, TypeError):
654
+ return default
655
+
656
+ def _get_by_key(self, key: str, default: Any = None) -> Any:
657
+ """Get a value by direct key."""
658
+ if self._root is None:
659
+ return default
660
+
661
+ try:
662
+ if isinstance(self._root, TreeGraphDictNode):
663
+ child = self._root._get_child(key)
664
+ return child._to_native()
665
+ elif isinstance(self._root, TreeGraphListNode):
666
+ try:
667
+ index = int(key)
668
+ child = self._root._get_child(index)
669
+ return child._to_native()
670
+ except ValueError:
671
+ return default
672
+ elif isinstance(self._root, TreeGraphValueNode):
673
+ # If root is a value node, only return it if key is empty or matches
674
+ if key == "" or key == "value":
675
+ return self._root._to_native()
676
+ return default
677
+ else:
678
+ return default
679
+
680
+ except (KeyError, IndexError, TypeError):
681
+ return default
682
+
683
+ def put(self, key: str, value: Any) -> None:
684
+ """Set a value by key."""
685
+ self._performance_tracker.record_access()
686
+
687
+ if self._root is None:
688
+ # Create root if it doesn't exist
689
+ self._root = TreeGraphDictNode({}, False)
690
+
691
+ # Handle path navigation
692
+ if '.' in key:
693
+ self._put_by_path(key, value)
694
+ else:
695
+ # Handle direct key access
696
+ if isinstance(self._root, TreeGraphDictNode):
697
+ # Create child node directly to avoid recursion
698
+ if value is None:
699
+ child = TreeGraphValueNode(None, self._root)
700
+ elif isinstance(value, (str, int, float, bool)):
701
+ child = TreeGraphValueNode(value, self._root)
702
+ elif isinstance(value, list):
703
+ is_lazy = len(value) > 100
704
+ child = TreeGraphListNode(value, is_lazy, self._root)
705
+ elif isinstance(value, dict):
706
+ is_lazy = len(value) > 100
707
+ child = TreeGraphDictNode(value, is_lazy, self._root)
708
+ else:
709
+ child = TreeGraphValueNode(value, self._root)
710
+
711
+ self._root._children[key] = child
712
+ self._root._invalidate_cache()
713
+
714
+ def _put_by_path(self, path: str, value: Any) -> None:
715
+ """Set a value by path."""
716
+ if self._root is None:
717
+ self._root = TreeGraphDictNode({}, False)
718
+
719
+ try:
720
+ segments = self._path_parser.parse(path)
721
+ current = self._root
722
+
723
+ # Navigate to parent of target
724
+ for segment in segments[:-1]:
725
+ if isinstance(current, TreeGraphDictNode):
726
+ if segment not in current._children:
727
+ current._children[segment] = TreeGraphDictNode({}, False)
728
+ current = current._children[segment]
729
+ elif isinstance(current, TreeGraphListNode):
730
+ try:
731
+ index = int(segment)
732
+ while len(current._children) <= index:
733
+ current._children.append(TreeGraphValueNode(None, current))
734
+ current = current._children[index]
735
+ except ValueError:
736
+ return
737
+ else:
738
+ return
739
+
740
+ # Set the final value
741
+ final_segment = segments[-1]
742
+ if isinstance(current, TreeGraphDictNode):
743
+ # Create child node directly to avoid recursion
744
+ if value is None:
745
+ child = TreeGraphValueNode(None, current)
746
+ elif isinstance(value, (str, int, float, bool)):
747
+ child = TreeGraphValueNode(value, current)
748
+ elif isinstance(value, list):
749
+ is_lazy = len(value) > 100
750
+ child = TreeGraphListNode(value, is_lazy, current)
751
+ elif isinstance(value, dict):
752
+ is_lazy = len(value) > 100
753
+ child = TreeGraphDictNode(value, is_lazy, current)
754
+ else:
755
+ child = TreeGraphValueNode(value, current)
756
+
757
+ current._children[final_segment] = child
758
+ current._invalidate_cache()
759
+ elif isinstance(current, TreeGraphListNode):
760
+ try:
761
+ index = int(final_segment)
762
+ while len(current._children) <= index:
763
+ current._children.append(TreeGraphValueNode(None, current))
764
+
765
+ # Create child node directly to avoid recursion
766
+ if value is None:
767
+ child = TreeGraphValueNode(None, current)
768
+ elif isinstance(value, (str, int, float, bool)):
769
+ child = TreeGraphValueNode(value, current)
770
+ elif isinstance(value, list):
771
+ is_lazy = len(value) > 100
772
+ child = TreeGraphListNode(value, is_lazy, current)
773
+ elif isinstance(value, dict):
774
+ is_lazy = len(value) > 100
775
+ child = TreeGraphDictNode(value, is_lazy, current)
776
+ else:
777
+ child = TreeGraphValueNode(value, current)
778
+
779
+ current._children[index] = child
780
+ current._invalidate_cache()
781
+ except ValueError:
782
+ return
783
+
784
+ except (KeyError, IndexError, TypeError):
785
+ pass
786
+
787
+ def has(self, key: str) -> bool:
788
+ """Check if key exists."""
789
+ return self.get_native(key) is not None
790
+
791
+ def delete(self, key: str) -> bool:
792
+ """Remove a key-value pair."""
793
+ # Implementation for deletion
794
+ # This would need to handle both direct keys and paths
795
+ return False
796
+
797
+ def remove(self, key: str) -> bool:
798
+ """Remove a key-value pair (alias for delete)."""
799
+ return self.delete(key)
800
+
801
+ def clear(self) -> None:
802
+ """Clear all data."""
803
+ self._root = None
804
+ self._size = 0
805
+
806
+ def keys(self) -> Iterator[str]:
807
+ """Get all keys."""
808
+ if self._root is None or not isinstance(self._root, TreeGraphDictNode):
809
+ return iter([])
810
+ # Trigger lazy loading if needed
811
+ if self._root._source_data is not None:
812
+ self._root._eager_load(self._root._source_data)
813
+ return self._root.keys()
814
+
815
+ def values(self) -> Iterator[Any]:
816
+ """Get all values."""
817
+ if self._root is None or not isinstance(self._root, TreeGraphDictNode):
818
+ return iter([])
819
+ # Trigger lazy loading if needed
820
+ if self._root._source_data is not None:
821
+ self._root._eager_load(self._root._source_data)
822
+ return (child._to_native() for child in self._root._children.values())
823
+
824
+ def items(self) -> Iterator[Tuple[str, Any]]:
825
+ """Get all key-value pairs."""
826
+ if self._root is None or not isinstance(self._root, TreeGraphDictNode):
827
+ return iter([])
828
+ # Trigger lazy loading if needed
829
+ if self._root._source_data is not None:
830
+ self._root._eager_load(self._root._source_data)
831
+ return ((key, child._to_native()) for key, child in self._root._children.items())
832
+
833
+ def __len__(self) -> int:
834
+ """Get the number of items."""
835
+ return self._size
836
+
837
+ def to_native(self) -> Any:
838
+ """Convert to native Python object."""
839
+ if self._root is None:
840
+ return {}
841
+ return self._root._to_native()
842
+
843
+ def backend_info(self) -> Dict[str, Any]:
844
+ """Get information about the backend implementation."""
845
+ return {
846
+ "strategy": "TREE_GRAPH_HYBRID",
847
+ "backend": "TreeGraphNode tree with lazy loading and advanced data structures",
848
+ "complexity": {
849
+ "get": "O(depth)",
850
+ "put": "O(depth)",
851
+ "has": "O(depth)",
852
+ "delete": "O(depth)",
853
+ "union_find": "O(α(n))",
854
+ "trie": "O(k) where k = word length",
855
+ "heap": "O(log n)"
856
+ },
857
+ "features": [
858
+ "lazy_loading",
859
+ "object_pooling",
860
+ "caching",
861
+ "tree_navigation",
862
+ "path_parsing",
863
+ "union_find",
864
+ "trie_operations",
865
+ "priority_queue",
866
+ "advanced_traits"
867
+ ]
868
+ }
869
+
870
+ def metrics(self) -> Dict[str, Any]:
871
+ """Get performance metrics."""
872
+ metrics = self._performance_tracker.get_metrics()
873
+ metrics.update({
874
+ "size": self._size,
875
+ "has_root": self._root is not None
876
+ })
877
+ return metrics
878
+
879
+ # ============================================================================
880
+ # ADVANCED DATA STRUCTURE OPERATIONS
881
+ # ============================================================================
882
+
883
+ def union_find_make_set(self, x: Any) -> None:
884
+ """Create new set with element x in Union-Find structure."""
885
+ uf = self._get_union_find()
886
+ uf.make_set(x)
887
+ self._save_union_find()
888
+
889
+ def union_find_find(self, x: Any) -> Any:
890
+ """Find root of set containing x in Union-Find structure."""
891
+ uf = self._get_union_find()
892
+ return uf.find(x)
893
+
894
+ def union_find_union(self, x: Any, y: Any) -> None:
895
+ """Union sets containing x and y in Union-Find structure."""
896
+ uf = self._get_union_find()
897
+ uf.union(x, y)
898
+ self._save_union_find()
899
+
900
+ def union_find_connected(self, x: Any, y: Any) -> bool:
901
+ """Check if x and y are in same set in Union-Find structure."""
902
+ uf = self._get_union_find()
903
+ return uf.connected(x, y)
904
+
905
+ def union_find_size(self) -> int:
906
+ """Get number of elements in Union-Find structure."""
907
+ uf = self._get_union_find()
908
+ return uf.size()
909
+
910
+ def union_find_sets_count(self) -> int:
911
+ """Get number of disjoint sets in Union-Find structure."""
912
+ uf = self._get_union_find()
913
+ return uf.sets_count()
914
+
915
+ def trie_insert(self, word: str, value: Any = None) -> None:
916
+ """Insert word into Trie structure."""
917
+ if not isinstance(word, str):
918
+ raise ValueError(f"Word must be string, got {type(word)}")
919
+ self._insert_trie_word(word, value)
920
+ self._save_trie()
921
+
922
+ def trie_contains(self, word: str) -> bool:
923
+ """Check if word exists in Trie structure."""
924
+ if not isinstance(word, str):
925
+ return False
926
+
927
+ current = self._get_trie()
928
+ for char in word:
929
+ if char not in current.children:
930
+ return False
931
+ current = current.children[char]
932
+
933
+ return current.is_end_word
934
+
935
+ def trie_get(self, word: str) -> Any:
936
+ """Get value associated with word in Trie structure."""
937
+ if not isinstance(word, str):
938
+ raise ValueError(f"Word must be string, got {type(word)}")
939
+
940
+ current = self._get_trie()
941
+ for char in word:
942
+ if char not in current.children:
943
+ raise ValueError(f"Word '{word}' not found in trie")
944
+ current = current.children[char]
945
+
946
+ return current.value
947
+
948
+ def trie_starts_with(self, prefix: str) -> List[str]:
949
+ """Find all words starting with prefix in Trie structure."""
950
+ if not isinstance(prefix, str):
951
+ return []
952
+
953
+ current = self._get_trie()
954
+ for char in prefix:
955
+ if char not in current.children:
956
+ return []
957
+ current = current.children[char]
958
+
959
+ # Collect all words from this node
960
+ result = {}
961
+ self._collect_trie_words(current, prefix, result)
962
+ return list(result.keys())
963
+
964
+ def heap_push(self, value: Any, priority: float = 0.0) -> None:
965
+ """Push item with priority into MinHeap."""
966
+ heap = self._get_heap()
967
+ heap.push(value, priority)
968
+ self._save_heap()
969
+
970
+ def heap_pop_min(self) -> Any:
971
+ """Pop minimum priority item from MinHeap."""
972
+ heap = self._get_heap()
973
+ result = heap.pop_min()
974
+ self._save_heap()
975
+ return result
976
+
977
+ def heap_peek_min(self) -> Any:
978
+ """Peek at minimum without removing from MinHeap."""
979
+ heap = self._get_heap()
980
+ return heap.peek_min()
981
+
982
+ def heap_size(self) -> int:
983
+ """Get heap size."""
984
+ heap = self._get_heap()
985
+ return heap.size()
986
+
987
+ def heap_is_empty(self) -> bool:
988
+ """Check if heap is empty."""
989
+ heap = self._get_heap()
990
+ return heap.is_empty()
991
+
992
+ # ============================================================================
993
+ # ADVANCED OPERATIONS HELPER METHODS
994
+ # ============================================================================
995
+
996
+ def _get_union_find(self) -> UnionFind:
997
+ """Get or create Union-Find structure from node data."""
998
+ if not hasattr(self, '_union_find'):
999
+ self._union_find = UnionFind()
1000
+ # Load existing data if available
1001
+ data = self.to_native()
1002
+ if isinstance(data, dict) and 'union_find' in data:
1003
+ uf_data = data['union_find']
1004
+ if isinstance(uf_data, dict):
1005
+ for element, parent in uf_data.get('sets', {}).items():
1006
+ self._union_find._parent[element] = parent
1007
+ for element, rank in uf_data.get('ranks', {}).items():
1008
+ self._union_find._rank[element] = rank
1009
+ self._union_find._sets_count = uf_data.get('sets_count', 0)
1010
+ return self._union_find
1011
+
1012
+ def _save_union_find(self) -> None:
1013
+ """Save Union-Find structure to node data."""
1014
+ if hasattr(self, '_union_find'):
1015
+ uf_data = {
1016
+ 'sets': dict(self._union_find._parent),
1017
+ 'ranks': dict(self._union_find._rank),
1018
+ 'sets_count': self._union_find._sets_count
1019
+ }
1020
+ # Save to node data
1021
+ current_data = self.to_native()
1022
+ if not isinstance(current_data, dict):
1023
+ current_data = {}
1024
+ current_data['union_find'] = uf_data
1025
+ # Update the strategy with new data
1026
+ self._root = TreeGraphNodeFactory.from_native(current_data, None)
1027
+
1028
+ def _get_trie(self) -> TrieNode:
1029
+ """Get or create Trie structure from node data."""
1030
+ if not hasattr(self, '_trie_root'):
1031
+ self._trie_root = TrieNode()
1032
+ # Load existing data if available
1033
+ data = self.to_native()
1034
+ if isinstance(data, dict):
1035
+ for word, value in data.items():
1036
+ if isinstance(word, str):
1037
+ self._insert_trie_word(word, value)
1038
+ return self._trie_root
1039
+
1040
+ def _insert_trie_word(self, word: str, value: Any) -> None:
1041
+ """Insert word into trie."""
1042
+ current = self._get_trie()
1043
+ for char in word:
1044
+ if char not in current.children:
1045
+ current.children[char] = TrieNode()
1046
+ current = current.children[char]
1047
+ current.is_end_word = True
1048
+ current.value = value
1049
+
1050
+ def _save_trie(self) -> None:
1051
+ """Save Trie structure to node data."""
1052
+ if hasattr(self, '_trie_root'):
1053
+ all_words = {}
1054
+ self._collect_trie_words(self._trie_root, "", all_words)
1055
+ # Save to node data
1056
+ current_data = self.to_native()
1057
+ if not isinstance(current_data, dict):
1058
+ current_data = {}
1059
+ current_data.update(all_words)
1060
+ # Update the strategy with new data
1061
+ self._root = TreeGraphNodeFactory.from_native(current_data, None)
1062
+
1063
+ def _collect_trie_words(self, node: TrieNode, prefix: str, result: Dict[str, Any]) -> None:
1064
+ """Recursively collect all words from trie."""
1065
+ if node.is_end_word:
1066
+ result[prefix] = node.value
1067
+
1068
+ for char, child in node.children.items():
1069
+ self._collect_trie_words(child, prefix + char, result)
1070
+
1071
+ def _get_heap(self) -> MinHeap:
1072
+ """Get or create MinHeap structure from node data."""
1073
+ if not hasattr(self, '_heap'):
1074
+ self._heap = MinHeap()
1075
+ # Load existing data if available
1076
+ data = self.to_native()
1077
+ if isinstance(data, dict) and 'heap' in data:
1078
+ heap_data = data['heap']
1079
+ if isinstance(heap_data, list):
1080
+ for priority, value in heap_data:
1081
+ self._heap.push(value, priority)
1082
+ return self._heap
1083
+
1084
+ def _save_heap(self) -> None:
1085
+ """Save MinHeap structure to node data."""
1086
+ if hasattr(self, '_heap'):
1087
+ heap_data = list(self._heap._heap)
1088
+ # Save to node data
1089
+ current_data = self.to_native()
1090
+ if not isinstance(current_data, dict):
1091
+ current_data = {}
1092
+ current_data['heap'] = heap_data
1093
+ # Update the strategy with new data
1094
+ self._root = TreeGraphNodeFactory.from_native(current_data, None)
1095
+
1096
+ # ============================================================================
1097
+ # REQUIRED INTERFACE METHODS
1098
+ # ============================================================================
1099
+
1100
+ def to_native(self) -> Any:
1101
+ """Convert to native Python object."""
1102
+ if self._root is None:
1103
+ return {}
1104
+ return self._root._to_native()
1105
+
1106
+ def get(self, path: str, default: Any = None) -> Optional['TreeGraphHybridStrategy']:
1107
+ """Get a child node by path."""
1108
+ if self._root is None:
1109
+ return None
1110
+
1111
+ try:
1112
+ if '.' in path:
1113
+ result = self._get_node_by_path(path)
1114
+ else:
1115
+ result = self._get_node_by_key(path)
1116
+
1117
+ if result is None:
1118
+ return None
1119
+
1120
+ # Create a new strategy instance with the result
1121
+ new_strategy = TreeGraphHybridStrategy()
1122
+ new_strategy._root = result
1123
+ return new_strategy
1124
+ except Exception:
1125
+ return None
1126
+
1127
+ def _get_node_by_path(self, path: str) -> Optional[TreeGraphNode]:
1128
+ """Get a node by path."""
1129
+ if self._root is None:
1130
+ return None
1131
+
1132
+ try:
1133
+ segments = self._path_parser.parse(path)
1134
+ current = self._root
1135
+
1136
+ for segment in segments:
1137
+ if isinstance(current, TreeGraphDictNode):
1138
+ current = current._get_child(segment)
1139
+ elif isinstance(current, TreeGraphListNode):
1140
+ try:
1141
+ index = int(segment)
1142
+ current = current._get_child(index)
1143
+ except ValueError:
1144
+ return None
1145
+ else:
1146
+ return None
1147
+
1148
+ return current
1149
+
1150
+ except (KeyError, IndexError, TypeError):
1151
+ return None
1152
+
1153
+ def _get_node_by_key(self, key: str) -> Optional[TreeGraphNode]:
1154
+ """Get a node by direct key."""
1155
+ if self._root is None:
1156
+ return None
1157
+
1158
+ try:
1159
+ if isinstance(self._root, TreeGraphDictNode):
1160
+ return self._root._get_child(key)
1161
+ elif isinstance(self._root, TreeGraphListNode):
1162
+ try:
1163
+ index = int(key)
1164
+ return self._root._get_child(index)
1165
+ except ValueError:
1166
+ return None
1167
+ elif isinstance(self._root, TreeGraphValueNode):
1168
+ # If root is a value node, only return it if key is empty or matches
1169
+ if key == "" or key == "value":
1170
+ return self._root
1171
+ return None
1172
+ else:
1173
+ return None
1174
+
1175
+ except (KeyError, IndexError, TypeError):
1176
+ return None
1177
+
1178
+ def put(self, path: str, value: Any) -> 'TreeGraphHybridStrategy':
1179
+ """Set a value at path."""
1180
+ if self._root is None:
1181
+ self._root = TreeGraphNodeFactory.from_native({})
1182
+
1183
+ # For now, implement a simple put operation
1184
+ # This would need to be enhanced for complex path navigation
1185
+ if '.' not in path:
1186
+ # Simple key assignment
1187
+ if isinstance(self._root, TreeGraphDictNode):
1188
+ value_node = TreeGraphNodeFactory.from_native(value, self._root)
1189
+ self._root._children[path] = value_node
1190
+ else:
1191
+ # Convert to dict if needed
1192
+ current_data = self.to_native()
1193
+ if not isinstance(current_data, dict):
1194
+ current_data = {}
1195
+ current_data[path] = value
1196
+ self._root = TreeGraphNodeFactory.from_native(current_data)
1197
+
1198
+ return self
1199
+
1200
+ def delete(self, path: str) -> bool:
1201
+ """Delete a node at path."""
1202
+ if self._root is None:
1203
+ return False
1204
+
1205
+ try:
1206
+ if '.' not in path:
1207
+ if isinstance(self._root, TreeGraphDictNode):
1208
+ if path in self._root._children:
1209
+ del self._root._children[path]
1210
+ return True
1211
+ return False
1212
+ except Exception:
1213
+ return False
1214
+
1215
+ def exists(self, path: str) -> bool:
1216
+ """Check if path exists."""
1217
+ return self.get(path) is not None
1218
+
1219
+ def keys(self) -> Iterator[str]:
1220
+ """Get keys (for dict-like nodes)."""
1221
+ if self._root is None:
1222
+ return iter([])
1223
+
1224
+ if isinstance(self._root, TreeGraphDictNode):
1225
+ return iter(self._root._children.keys())
1226
+ elif isinstance(self._root, TreeGraphListNode):
1227
+ return iter(str(i) for i in range(len(self._root._children)))
1228
+ else:
1229
+ return iter([])
1230
+
1231
+ def values(self) -> Iterator['TreeGraphHybridStrategy']:
1232
+ """Get values (for dict-like nodes)."""
1233
+ if self._root is None:
1234
+ return iter([])
1235
+
1236
+ if isinstance(self._root, TreeGraphDictNode):
1237
+ for child in self._root._children.values():
1238
+ new_strategy = TreeGraphHybridStrategy()
1239
+ new_strategy._root = child
1240
+ yield new_strategy
1241
+ elif isinstance(self._root, TreeGraphListNode):
1242
+ for child in self._root._children:
1243
+ new_strategy = TreeGraphHybridStrategy()
1244
+ new_strategy._root = child
1245
+ yield new_strategy
1246
+ else:
1247
+ return iter([])
1248
+
1249
+ def items(self) -> Iterator[tuple[str, 'TreeGraphHybridStrategy']]:
1250
+ """Get items (for dict-like nodes)."""
1251
+ if self._root is None:
1252
+ return iter([])
1253
+
1254
+ if isinstance(self._root, TreeGraphDictNode):
1255
+ for key, child in self._root._children.items():
1256
+ new_strategy = TreeGraphHybridStrategy()
1257
+ new_strategy._root = child
1258
+ yield (key, new_strategy)
1259
+ elif isinstance(self._root, TreeGraphListNode):
1260
+ for i, child in enumerate(self._root._children):
1261
+ new_strategy = TreeGraphHybridStrategy()
1262
+ new_strategy._root = child
1263
+ yield (str(i), new_strategy)
1264
+ else:
1265
+ return iter([])
1266
+
1267
+ def __len__(self) -> int:
1268
+ """Get length."""
1269
+ if self._root is None:
1270
+ return 0
1271
+
1272
+ if isinstance(self._root, TreeGraphDictNode):
1273
+ return len(self._root._children)
1274
+ elif isinstance(self._root, TreeGraphListNode):
1275
+ return len(self._root._children)
1276
+ else:
1277
+ return 1
1278
+
1279
+ def __iter__(self) -> Iterator['TreeGraphHybridStrategy']:
1280
+ """Iterate over children."""
1281
+ return self.values()
1282
+
1283
+ def __getitem__(self, key: Union[str, int]) -> 'TreeGraphHybridStrategy':
1284
+ """Get child by key or index."""
1285
+ if self._root is None:
1286
+ raise KeyError(f"Key '{key}' not found")
1287
+
1288
+ if isinstance(self._root, TreeGraphDictNode):
1289
+ if key not in self._root._children:
1290
+ raise KeyError(f"Key '{key}' not found")
1291
+ child = self._root._children[key]
1292
+ elif isinstance(self._root, TreeGraphListNode):
1293
+ if not isinstance(key, int):
1294
+ raise TypeError("List indices must be integers")
1295
+ if key < 0 or key >= len(self._root._children):
1296
+ raise IndexError("List index out of range")
1297
+ child = self._root._children[key]
1298
+ else:
1299
+ raise TypeError(f"Cannot access key '{key}' on node of type {type(self._root)}")
1300
+
1301
+ new_strategy = TreeGraphHybridStrategy()
1302
+ new_strategy._root = child
1303
+ return new_strategy
1304
+
1305
+ def __setitem__(self, key: Union[str, int], value: Any) -> None:
1306
+ """Set child by key or index."""
1307
+ if self._root is None:
1308
+ self._root = TreeGraphNodeFactory.from_native({})
1309
+
1310
+ if isinstance(self._root, TreeGraphDictNode):
1311
+ value_node = TreeGraphNodeFactory.from_native(value, self._root)
1312
+ self._root._children[key] = value_node
1313
+ elif isinstance(self._root, TreeGraphListNode):
1314
+ if not isinstance(key, int):
1315
+ raise TypeError("List indices must be integers")
1316
+ value_node = TreeGraphNodeFactory.from_native(value, self._root)
1317
+ if key >= len(self._root._children):
1318
+ # Extend list if needed
1319
+ while len(self._root._children) <= key:
1320
+ self._root._children.append(TreeGraphNodeFactory.from_native(None, self._root))
1321
+ self._root._children[key] = value_node
1322
+ else:
1323
+ raise TypeError(f"Cannot set key '{key}' on node of type {type(self._root)}")
1324
+
1325
+ def __contains__(self, key: Union[str, int]) -> bool:
1326
+ """Check if key exists."""
1327
+ if self._root is None:
1328
+ return False
1329
+
1330
+ if isinstance(self._root, TreeGraphDictNode):
1331
+ return key in self._root._children
1332
+ elif isinstance(self._root, TreeGraphListNode):
1333
+ if not isinstance(key, int):
1334
+ return False
1335
+ return 0 <= key < len(self._root._children)
1336
+ else:
1337
+ return False
1338
+
1339
+ # Type checking properties
1340
+ @property
1341
+ def is_leaf(self) -> bool:
1342
+ """Check if this is a leaf node."""
1343
+ if self._root is None:
1344
+ return True
1345
+ return isinstance(self._root, TreeGraphValueNode)
1346
+
1347
+ @property
1348
+ def is_list(self) -> bool:
1349
+ """Check if this is a list node."""
1350
+ if self._root is None:
1351
+ return False
1352
+ return isinstance(self._root, TreeGraphListNode)
1353
+
1354
+ @property
1355
+ def is_dict(self) -> bool:
1356
+ """Check if this is a dict node."""
1357
+ if self._root is None:
1358
+ return False
1359
+ return isinstance(self._root, TreeGraphDictNode)
1360
+
1361
+ @property
1362
+ def is_reference(self) -> bool:
1363
+ """Check if this is a reference node."""
1364
+ if self._root is None:
1365
+ return False
1366
+ return isinstance(self._root, TreeGraphReferenceNode)
1367
+
1368
+ @property
1369
+ def is_object(self) -> bool:
1370
+ """Check if this is an object node."""
1371
+ if self._root is None:
1372
+ return False
1373
+ return isinstance(self._root, TreeGraphObjectNode)
1374
+
1375
+ @property
1376
+ def type(self) -> str:
1377
+ """Get the type of this node."""
1378
+ if self._root is None:
1379
+ return 'empty'
1380
+ elif isinstance(self._root, TreeGraphValueNode):
1381
+ return 'value'
1382
+ elif isinstance(self._root, TreeGraphListNode):
1383
+ return 'list'
1384
+ elif isinstance(self._root, TreeGraphDictNode):
1385
+ return 'dict'
1386
+ elif isinstance(self._root, TreeGraphReferenceNode):
1387
+ return 'reference'
1388
+ elif isinstance(self._root, TreeGraphObjectNode):
1389
+ return 'object'
1390
+ else:
1391
+ return 'unknown'
1392
+
1393
+ @property
1394
+ def value(self) -> Any:
1395
+ """Get the value of this node."""
1396
+ if self._root is None:
1397
+ return None
1398
+ return self._root._to_native()
1399
+
1400
+ # Optional properties with default implementations
1401
+ @property
1402
+ def uri(self) -> Optional[str]:
1403
+ """Get URI (for reference/object nodes)."""
1404
+ if self._root is None:
1405
+ return None
1406
+ return getattr(self._root, 'uri', None)
1407
+
1408
+ @property
1409
+ def reference_type(self) -> Optional[str]:
1410
+ """Get reference type (for reference nodes)."""
1411
+ if self._root is None:
1412
+ return None
1413
+ return getattr(self._root, 'reference_type', None)
1414
+
1415
+ @property
1416
+ def object_type(self) -> Optional[str]:
1417
+ """Get object type (for object nodes)."""
1418
+ if self._root is None:
1419
+ return None
1420
+ return getattr(self._root, 'object_type', None)
1421
+
1422
+ @property
1423
+ def mime_type(self) -> Optional[str]:
1424
+ """Get MIME type (for object nodes)."""
1425
+ if self._root is None:
1426
+ return None
1427
+ return getattr(self._root, 'mime_type', None)
1428
+
1429
+ @property
1430
+ def metadata(self) -> Optional[Dict[str, Any]]:
1431
+ """Get metadata (for reference/object nodes)."""
1432
+ if self._root is None:
1433
+ return None
1434
+ return getattr(self._root, 'metadata', None)