1use crate::cursor::{EdgeCursor, IndexCursor, IndexRow, IndexScanPlan, ScanOptions, VertexCursor};
4use crate::schema::{LabelVersionHistory, PropertyChange};
5use linkrs_core::types::{EdgeTypeInfo, Index, SpaceInfo, TagInfo, VertexId};
6use linkrs_core::{Edge, EdgeDirection, StorageError, Value, Vertex};
7use std::sync::Arc;
8
9pub trait StorageReader: Send + Sync + std::fmt::Debug {
11 fn get_vertex(
12 &self,
13 space: &str,
14 tag: &str,
15 id: &VertexId,
16 ) -> Result<Option<Vertex>, StorageError>;
17
18 fn layout_version(&self) -> u64 {
24 0
25 }
26
27 fn vertex_id_domain(&self, space: &str) -> Option<std::ops::Range<i64>> {
34 let _ = space;
35 None
36 }
37
38 fn get_vertex_projected(
44 &self,
45 space: &str,
46 tag: &str,
47 id: &VertexId,
48 projection: &[std::sync::Arc<str>],
49 ) -> Result<Option<Vertex>, StorageError> {
50 let vertex = self.get_vertex(space, tag, id)?;
51 if projection.is_empty() {
52 return Ok(vertex);
53 }
54 Ok(vertex.map(|mut v| {
55 v.tag.properties.retain(|k, _| projection.contains(k));
56 v
57 }))
58 }
59
60 fn scan_vertices(&self, space: &str) -> Result<Vec<Vertex>, StorageError>;
61 fn scan_vertices_by_tag(&self, space: &str, tag: &str) -> Result<Vec<Vertex>, StorageError>;
62 fn scan_vertices_by_tag_paginated(
63 &self,
64 space: &str,
65 tag: &str,
66 offset: usize,
67 limit: usize,
68 ) -> Result<Vec<Vertex>, StorageError> {
69 let _ = (space, tag, offset, limit);
70 Err(StorageError::not_supported(
71 "Native vertex pagination is not supported by this storage implementation",
72 ))
73 }
74 fn scan_vertices_by_prop(
75 &self,
76 space: &str,
77 tag: &str,
78 prop: &str,
79 value: &Value,
80 ) -> Result<Vec<Vertex>, StorageError>;
81
82 fn get_edge(
83 &self,
84 space: &str,
85 src: &VertexId,
86 dst: &VertexId,
87 edge_type: &str,
88 rank: i64,
89 ) -> Result<Option<Edge>, StorageError>;
90
91 fn get_edge_projected(
97 &self,
98 space: &str,
99 src: &VertexId,
100 dst: &VertexId,
101 edge_type: &str,
102 rank: i64,
103 projection: &[Arc<str>],
104 ) -> Result<Option<Edge>, StorageError> {
105 let edge = self.get_edge(space, src, dst, edge_type, rank)?;
106 if projection.is_empty() {
107 return Ok(edge);
108 }
109 Ok(edge.map(|mut e| {
110 e.props.retain(|k, _| projection.contains(k));
111 e
112 }))
113 }
114 fn get_node_edges(
115 &self,
116 space: &str,
117 node_id: &VertexId,
118 direction: EdgeDirection,
119 edge_types: &[String],
120 ) -> Result<Vec<Edge>, StorageError>;
121
122 fn get_node_edges_projected(
131 &self,
132 space: &str,
133 node_id: &VertexId,
134 direction: EdgeDirection,
135 edge_types: &[String],
136 projection: Option<&[Arc<str>]>,
137 limit: Option<usize>,
138 ) -> Result<Vec<Edge>, StorageError> {
139 let mut edges = self.get_node_edges(space, node_id, direction, edge_types)?;
140 if let Some(projection) = projection {
141 if !projection.is_empty() {
142 for edge in &mut edges {
143 edge.props.retain(|k, _| projection.contains(k));
144 }
145 } else {
146 for edge in &mut edges {
147 edge.props.clear();
148 }
149 }
150 }
151 if let Some(limit) = limit {
152 edges.truncate(limit);
153 }
154 Ok(edges)
155 }
156
157 fn get_vertices_batch(
163 &self,
164 space: &str,
165 tag: &str,
166 ids: &[VertexId],
167 ) -> Result<Vec<Option<Vertex>>, StorageError> {
168 let mut out = Vec::with_capacity(ids.len());
169 for id in ids {
170 out.push(self.get_vertex(space, tag, id)?);
171 }
172 Ok(out)
173 }
174
175 fn get_vertices_projected_batch(
186 &self,
187 space: &str,
188 tag: &str,
189 ids: &[VertexId],
190 projection: &[std::sync::Arc<str>],
191 ) -> Result<Vec<Option<Vertex>>, StorageError> {
192 let mut out = Vec::with_capacity(ids.len());
193 for id in ids {
194 out.push(self.get_vertex_projected(space, tag, id, projection)?);
195 }
196 Ok(out)
197 }
198
199 fn edge_types_ttl_active(
212 &self,
213 space: &str,
214 edge_types: &[String],
215 ) -> Result<bool, StorageError> {
216 let is_active = |info: &EdgeTypeInfo| {
217 linkrs_core::types::ttl::has_valid_ttl(info.ttl_duration, info.ttl_col.as_deref())
218 };
219 if edge_types.is_empty() {
220 Ok(self.list_edge_types(space)?.iter().any(is_active))
221 } else {
222 for name in edge_types {
223 if let Some(info) = self.get_edge_type(space, name)? {
224 if is_active(&info) {
225 return Ok(true);
226 }
227 }
228 }
229 Ok(false)
230 }
231 }
232
233 fn neighbor_dst_ids_batch(
241 &self,
242 space: &str,
243 src_ids: &[VertexId],
244 direction: EdgeDirection,
245 edge_types: &[String],
246 ) -> Result<Vec<Vec<VertexId>>, StorageError>;
247
248 fn out_degree_batch(
251 &self,
252 space: &str,
253 src_ids: &[VertexId],
254 direction: EdgeDirection,
255 edge_types: &[String],
256 ) -> Result<Vec<usize>, StorageError>;
257
258 fn scan_edges_by_type(&self, space: &str, edge_type: &str) -> Result<Vec<Edge>, StorageError>;
259 fn scan_edges_by_type_parallel(
265 &self,
266 space: &str,
267 edge_type: &str,
268 shards: usize,
269 ) -> Result<Vec<Edge>, StorageError> {
270 let _ = shards;
271 self.scan_edges_by_type(space, edge_type)
272 }
273 fn scan_all_edges(&self, space: &str) -> Result<Vec<Edge>, StorageError>;
274 fn count_vertices_by_tag(&self, space: &str, tag: &str) -> Result<u64, StorageError>;
275 fn count_edges_by_type(&self, space: &str, edge_type: &str) -> Result<u64, StorageError>;
276
277 fn scan_edges_by_type_paginated(
282 &self,
283 space: &str,
284 edge_type: &str,
285 offset: usize,
286 limit: usize,
287 ) -> Result<Vec<Edge>, StorageError> {
288 let _ = (space, edge_type, offset, limit);
289 Err(StorageError::not_supported(
290 "Native edge pagination is not supported by this storage implementation",
291 ))
292 }
293
294 fn lookup_index(
295 &self,
296 space: &str,
297 index: &str,
298 value: &Value,
299 ) -> Result<Vec<Value>, StorageError>;
300
301 fn enable_edge_property_index(
304 &self,
305 space: &str,
306 edge_type: &str,
307 pool_capacity: u64,
308 ) -> Result<bool, StorageError> {
309 let _ = (space, edge_type, pool_capacity);
310 Err(StorageError::not_supported(
311 "Edge property index management is not supported by this storage implementation",
312 ))
313 }
314
315 fn has_edge_property_index(&self, space: &str, edge_type: &str) -> Result<bool, StorageError> {
317 let _ = (space, edge_type);
318 Err(StorageError::not_supported(
319 "Edge property index management is not supported by this storage implementation",
320 ))
321 }
322
323 fn disable_edge_property_index(
325 &self,
326 space: &str,
327 edge_type: &str,
328 ) -> Result<(), StorageError> {
329 let _ = (space, edge_type);
330 Err(StorageError::not_supported(
331 "Edge property index management is not supported by this storage implementation",
332 ))
333 }
334
335 #[allow(clippy::too_many_arguments)]
341 fn lookup_edges_by_property_range(
342 &self,
343 space: &str,
344 edge_type: &str,
345 prop_name: &str,
346 lower: Option<&Value>,
347 upper: Option<&Value>,
348 include_lower: bool,
349 include_upper: bool,
350 ) -> Result<Vec<Edge>, StorageError> {
351 let _ = (
352 space,
353 edge_type,
354 prop_name,
355 lower,
356 upper,
357 include_lower,
358 include_upper,
359 );
360 Err(StorageError::not_supported(
361 "Edge property range lookup is not supported by this storage implementation",
362 ))
363 }
364
365 fn get_vertex_with_schema(
366 &self,
367 space: &str,
368 tag: &str,
369 id: &Value,
370 ) -> Result<Option<(TagInfo, Vec<u8>)>, StorageError>;
371 fn get_edge_with_schema(
372 &self,
373 space: &str,
374 edge_type: &str,
375 src: &Value,
376 dst: &Value,
377 ) -> Result<Option<(EdgeTypeInfo, Vec<u8>)>, StorageError>;
378 fn scan_vertices_with_schema(
379 &self,
380 space: &str,
381 tag: &str,
382 ) -> Result<Vec<(TagInfo, Vec<u8>)>, StorageError>;
383 fn scan_edges_with_schema(
384 &self,
385 space: &str,
386 edge_type: &str,
387 ) -> Result<Vec<(EdgeTypeInfo, Vec<u8>)>, StorageError>;
388
389 fn get_space(&self, space: &str) -> Result<Option<SpaceInfo>, StorageError>;
390 fn get_space_by_id(&self, space_id: u64) -> Result<Option<SpaceInfo>, StorageError>;
391 fn list_spaces(&self) -> Result<Vec<SpaceInfo>, StorageError>;
392 fn get_space_id(&self, space: &str) -> Result<u64, StorageError>;
393 fn space_exists(&self, space: &str) -> bool;
394
395 fn get_tag(&self, space: &str, tag: &str) -> Result<Option<TagInfo>, StorageError>;
396 fn list_tags(&self, space: &str) -> Result<Vec<TagInfo>, StorageError>;
397
398 fn get_edge_type(
399 &self,
400 space: &str,
401 edge_type: &str,
402 ) -> Result<Option<EdgeTypeInfo>, StorageError>;
403 fn list_edge_types(&self, space: &str) -> Result<Vec<EdgeTypeInfo>, StorageError>;
404
405 fn resolve_edge_type_name(
413 &self,
414 space: &str,
415 hash: u32,
416 ) -> Result<Option<String>, StorageError> {
417 let edge_types = self.list_edge_types(space)?;
418 Ok(edge_types.into_iter().find_map(|edge_type| {
419 if crate::index::helpers::stable_hash(edge_type.edge_type_name.as_bytes()) as u32
420 == hash
421 {
422 Some(edge_type.edge_type_name)
423 } else {
424 None
425 }
426 }))
427 }
428
429 fn get_tag_index(&self, space: &str, index: &str) -> Result<Option<Index>, StorageError>;
430 fn list_tag_indexes(&self, space: &str) -> Result<Vec<Index>, StorageError>;
431
432 fn get_edge_index(&self, space: &str, index: &str) -> Result<Option<Index>, StorageError>;
433 fn list_edge_indexes(&self, space: &str) -> Result<Vec<Index>, StorageError>;
434
435 fn get_vertex_version_history(
438 &self,
439 space: &str,
440 tag: &str,
441 ) -> Result<Option<LabelVersionHistory>, StorageError>;
442
443 fn get_edge_version_history(
445 &self,
446 space: &str,
447 edge_type: &str,
448 ) -> Result<Option<LabelVersionHistory>, StorageError>;
449
450 fn get_vertex_schema_changes(
452 &self,
453 space: &str,
454 tag: &str,
455 from_version: u64,
456 to_version: u64,
457 ) -> Result<Vec<PropertyChange>, StorageError>;
458
459 fn get_edge_schema_changes(
461 &self,
462 space: &str,
463 edge_type: &str,
464 from_version: u64,
465 to_version: u64,
466 ) -> Result<Vec<PropertyChange>, StorageError>;
467
468 fn detect_vertex_breaking_changes(
470 &self,
471 space: &str,
472 tag: &str,
473 from_version: u64,
474 to_version: u64,
475 ) -> Result<Vec<PropertyChange>, StorageError>;
476
477 fn detect_edge_breaking_changes(
479 &self,
480 space: &str,
481 edge_type: &str,
482 from_version: u64,
483 to_version: u64,
484 ) -> Result<Vec<PropertyChange>, StorageError>;
485
486 fn create_vertex_cursor(
492 &self,
493 _space: &str,
494 _options: &ScanOptions,
495 ) -> Result<Box<dyn VertexCursor>, StorageError> {
496 Err(StorageError::not_supported(
497 "Native vertex cursor is not supported by this storage implementation",
498 ))
499 }
500
501 fn create_edge_cursor(
505 &self,
506 _space: &str,
507 _options: &ScanOptions,
508 ) -> Result<Box<dyn EdgeCursor>, StorageError> {
509 Err(StorageError::not_supported(
510 "Native edge cursor is not supported by this storage implementation",
511 ))
512 }
513
514 fn create_index_cursor(
520 &self,
521 _plan: &IndexScanPlan,
522 ) -> Result<Box<dyn IndexCursor<Row = IndexRow>>, StorageError> {
523 Err(StorageError::not_supported(
524 "Native index cursor is not supported by this storage engine",
525 ))
526 }
527
528 fn list_migration_history(
531 &self,
532 _space: &str,
533 _label: &str,
534 _is_edge: bool,
535 ) -> Result<Vec<crate::MigrationHistoryRecord>, StorageError> {
536 Err(StorageError::not_supported(
537 "Migration history is not supported by this storage implementation",
538 ))
539 }
540
541 fn get_applied_versions(
542 &self,
543 _space: &str,
544 _label: &str,
545 _is_edge: bool,
546 ) -> Result<Vec<u64>, StorageError> {
547 Err(StorageError::not_supported(
548 "Migration history is not supported by this storage implementation",
549 ))
550 }
551
552 fn record_migration_history(
553 &self,
554 _record: crate::MigrationHistoryRecord,
555 ) -> Result<(), StorageError> {
556 Err(StorageError::not_supported(
557 "Migration history is not supported by this storage implementation",
558 ))
559 }
560
561 fn list_all_migration_history(
562 &self,
563 ) -> Result<Vec<crate::MigrationHistoryRecord>, StorageError> {
564 Err(StorageError::not_supported(
565 "Migration history is not supported by this storage implementation",
566 ))
567 }
568}