Coverage for src / lexigram / contracts / data / graph / protocols.py: 0%
39 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
1"""Graph store protocol definitions."""
3from __future__ import annotations
5from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
7from lexigram.contracts.data.graph.enums import EdgeDirection
9if TYPE_CHECKING:
10 from lexigram.contracts.core.health import HealthCheckResult
11 from lexigram.contracts.data.graph.filters import PropertyFilter
12 from lexigram.contracts.data.graph.types import (
13 BulkEdgeResult,
14 BulkNodeResult,
15 ConstraintSpec,
16 EdgeResult,
17 EdgeSpec,
18 GraphEdge,
19 GraphInfo,
20 GraphNode,
21 GraphPath,
22 IndexSpec,
23 NodeResult,
24 NodeSpec,
25 TraversalQuery,
26 )
29@runtime_checkable
30class GraphStoreProtocol(Protocol):
31 """Top-level graph store lifecycle and database management.
33 Manages connections to the graph backend and provides access to
34 individual graph databases.
35 """
37 async def connect(self) -> None:
38 """Establish connection to the graph store."""
39 ...
41 async def disconnect(self) -> None:
42 """Close all connections and release resources."""
43 ...
45 async def health_check(self, timeout: float = 5.0) -> HealthCheckResult:
46 """Check store connectivity and readiness."""
47 ...
49 async def get_graph(self, name: str | None = None) -> GraphProtocol:
50 """Get a handle to a graph database.
52 Args:
53 name: Database name. ``None`` returns the default graph.
55 Raises:
56 GraphNotFoundError: If the named graph does not exist.
57 """
58 ...
60 async def list_graphs(self) -> list[GraphInfo]:
61 """List all available graph databases."""
62 ...
64 async def create_graph(self, name: str) -> None:
65 """Create a new graph database.
67 Raises:
68 GraphAlreadyExistsError: If the graph already exists.
69 """
70 ...
72 async def delete_graph(self, name: str) -> None:
73 """Delete a graph database and all its data.
75 Raises:
76 GraphNotFoundError: If the graph does not exist.
77 """
78 ...
81@runtime_checkable
82class GraphProtocol(Protocol):
83 """All operations on a single graph database.
85 Provides CRUD for nodes and edges, traversal queries, raw query
86 passthrough, bulk operations, and schema management.
87 """
89 # ── Node Operations ───────────────────────────────────────────
91 async def create_node(
92 self,
93 labels: list[str],
94 properties: dict[str, Any] | None = None,
95 node_id: str | None = None,
96 ) -> NodeResult:
97 """Create a node with labels and properties."""
98 ...
100 async def get_node(self, node_id: str) -> GraphNode | None:
101 """Retrieve a node by ID. Returns None if not found."""
102 ...
104 async def find_nodes(
105 self,
106 labels: list[str] | None = None,
107 filter: PropertyFilter | None = None,
108 limit: int = 100,
109 skip: int = 0,
110 ) -> list[GraphNode]:
111 """Find nodes matching labels and/or property filter."""
112 ...
114 async def update_node(
115 self,
116 node_id: str,
117 properties: dict[str, Any],
118 merge: bool = True,
119 ) -> bool:
120 """Update node properties."""
121 ...
123 async def delete_node(
124 self,
125 node_id: str,
126 detach: bool = True,
127 ) -> bool:
128 """Delete a node."""
129 ...
131 async def neighbors(
132 self,
133 node_id: str,
134 depth: int = 1,
135 direction: EdgeDirection = EdgeDirection.BOTH,
136 edge_types: list[str] | None = None,
137 ) -> list[GraphNode]:
138 """Get neighbouring nodes reachable within the given depth."""
139 ...
141 async def count_nodes(self) -> int:
142 """Return the total number of nodes in the graph."""
143 ...
145 async def count_edges(self) -> int:
146 """Return the total number of edges in the graph."""
147 ...
149 async def get_labels(self) -> list[str]:
150 """Return all unique node labels in the graph."""
151 ...
153 async def get_edge_types(self) -> list[str]:
154 """Return all unique edge types in the graph."""
155 ...
157 # ── Edge Operations ───────────────────────────────────────────
159 async def create_edge(
160 self,
161 source_id: str,
162 target_id: str,
163 edge_type: str,
164 properties: dict[str, Any] | None = None,
165 ) -> EdgeResult:
166 """Create a directed edge between two nodes."""
167 ...
169 async def get_edge(self, edge_id: str) -> GraphEdge | None:
170 """Retrieve an edge by ID."""
171 ...
173 async def get_edges(
174 self,
175 node_id: str,
176 direction: EdgeDirection = EdgeDirection.BOTH,
177 edge_types: list[str] | None = None,
178 limit: int = 100,
179 ) -> list[GraphEdge]:
180 """Get edges connected to a node."""
181 ...
183 async def update_edge(
184 self,
185 edge_id: str,
186 properties: dict[str, Any],
187 merge: bool = True,
188 ) -> bool:
189 """Update edge properties."""
190 ...
192 async def delete_edge(self, edge_id: str) -> bool:
193 """Delete an edge by ID."""
194 ...
196 # ── Traversal ─────────────────────────────────────────────────
198 async def traverse(
199 self,
200 query: TraversalQuery,
201 ) -> list[GraphPath]:
202 """Execute a traversal query and return matching paths."""
203 ...
205 async def shortest_path(
206 self,
207 from_id: str,
208 to_id: str,
209 max_depth: int = 10,
210 edge_types: list[str] | None = None,
211 direction: EdgeDirection = EdgeDirection.BOTH,
212 ) -> GraphPath | None:
213 """Find the shortest path between two nodes."""
214 ...
216 # ── Raw Query ─────────────────────────────────────────────────
218 async def query(
219 self,
220 query_string: str,
221 parameters: dict[str, Any] | None = None,
222 ) -> list[dict[str, Any]]:
223 """Execute a raw backend-specific query (Cypher, Gremlin, etc.)."""
224 ...
226 # ── Bulk Operations ───────────────────────────────────────────
228 async def bulk_create_nodes(
229 self,
230 nodes: list[NodeSpec],
231 ) -> BulkNodeResult:
232 """Create multiple nodes in a single operation."""
233 ...
235 async def bulk_create_edges(
236 self,
237 edges: list[EdgeSpec],
238 ) -> BulkEdgeResult:
239 """Create multiple edges in a single operation."""
240 ...
242 # ── Schema ────────────────────────────────────────────────────
244 async def create_index(self, spec: IndexSpec) -> None:
245 """Create an index on node label + properties."""
246 ...
248 async def drop_index(self, name: str) -> None:
249 """Drop an index by name."""
250 ...
252 async def create_constraint(self, spec: ConstraintSpec) -> None:
253 """Create a schema constraint."""
254 ...
256 async def drop_constraint(self, name: str) -> None:
257 """Drop a constraint by name."""
258 ...
261__all__ = [
262 "GraphProtocol",
263 "GraphStoreProtocol",
264]