1use crate::spatial::LoraPoint;
2use crate::temporal::{
3 LoraDate, LoraDateTime, LoraDuration, LoraLocalDateTime, LoraLocalTime, LoraTime,
4};
5use crate::vector::LoraVector;
6use lora_ast::Direction;
7use std::collections::{BTreeMap, BTreeSet};
8
9pub type NodeId = u64;
10pub type RelationshipId = u64;
11
12#[derive(Debug, Clone, PartialEq)]
13pub enum PropertyValue {
14 Null,
15 Bool(bool),
16 Int(i64),
17 Float(f64),
18 String(String),
19 List(Vec<PropertyValue>),
20 Map(BTreeMap<String, PropertyValue>),
21 Date(LoraDate),
22 Time(LoraTime),
23 LocalTime(LoraLocalTime),
24 DateTime(LoraDateTime),
25 LocalDateTime(LoraLocalDateTime),
26 Duration(LoraDuration),
27 Point(LoraPoint),
28 Vector(LoraVector),
29}
30
31pub type Properties = BTreeMap<String, PropertyValue>;
32
33#[derive(Debug, Clone, PartialEq)]
34pub struct NodeRecord {
35 pub id: NodeId,
36 pub labels: Vec<String>,
37 pub properties: Properties,
38}
39
40impl NodeRecord {
41 pub fn has_label(&self, label: &str) -> bool {
42 self.labels.iter().any(|l| l == label)
43 }
44
45 pub fn property(&self, key: &str) -> Option<&PropertyValue> {
46 self.properties.get(key)
47 }
48}
49
50#[derive(Debug, Clone, PartialEq)]
51pub struct RelationshipRecord {
52 pub id: RelationshipId,
53 pub src: NodeId,
54 pub dst: NodeId,
55 pub rel_type: String,
56 pub properties: Properties,
57}
58
59impl RelationshipRecord {
60 pub fn property(&self, key: &str) -> Option<&PropertyValue> {
61 self.properties.get(key)
62 }
63
64 pub fn other_node(&self, node_id: NodeId) -> Option<NodeId> {
65 if self.src == node_id {
66 Some(self.dst)
67 } else if self.dst == node_id {
68 Some(self.src)
69 } else {
70 None
71 }
72 }
73
74 pub fn matches_direction_from(&self, node_id: NodeId, direction: Direction) -> bool {
75 match direction {
76 Direction::Right => self.src == node_id,
77 Direction::Left => self.dst == node_id,
78 Direction::Undirected => self.src == node_id || self.dst == node_id,
79 }
80 }
81}
82
83#[derive(Debug, Clone, PartialEq)]
84pub struct ExpandedRelationship {
85 pub relationship: RelationshipRecord,
86 pub other_node: NodeRecord,
87}
88
89pub trait GraphStorage {
90 fn all_nodes(&self) -> Vec<NodeRecord>;
93 fn nodes_by_label(&self, label: &str) -> Vec<NodeRecord>;
94
95 fn node_ref(&self, id: NodeId) -> Option<&NodeRecord>;
99
100 fn node(&self, id: NodeId) -> Option<NodeRecord> {
101 self.node_ref(id).cloned()
102 }
103
104 fn has_node(&self, id: NodeId) -> bool {
105 self.node_ref(id).is_some()
106 }
107
108 fn node_count(&self) -> usize {
109 self.all_node_ids().len()
110 }
111
112 fn all_node_ids(&self) -> Vec<NodeId> {
115 self.all_nodes().into_iter().map(|n| n.id).collect()
116 }
117
118 fn node_ids_by_label(&self, label: &str) -> Vec<NodeId> {
120 self.nodes_by_label(label)
121 .into_iter()
122 .map(|n| n.id)
123 .collect()
124 }
125
126 fn all_relationships(&self) -> Vec<RelationshipRecord>;
129 fn relationships_by_type(&self, rel_type: &str) -> Vec<RelationshipRecord>;
130
131 fn relationship_ref(&self, id: RelationshipId) -> Option<&RelationshipRecord>;
132
133 fn relationship(&self, id: RelationshipId) -> Option<RelationshipRecord> {
134 self.relationship_ref(id).cloned()
135 }
136
137 fn has_relationship(&self, id: RelationshipId) -> bool {
138 self.relationship_ref(id).is_some()
139 }
140
141 fn relationship_count(&self) -> usize {
142 self.all_rel_ids().len()
143 }
144
145 fn all_rel_ids(&self) -> Vec<RelationshipId> {
146 self.all_relationships().into_iter().map(|r| r.id).collect()
147 }
148
149 fn rel_ids_by_type(&self, rel_type: &str) -> Vec<RelationshipId> {
150 self.relationships_by_type(rel_type)
151 .into_iter()
152 .map(|r| r.id)
153 .collect()
154 }
155
156 fn all_labels(&self) -> Vec<String> {
159 let mut labels = BTreeSet::new();
160 for node in self.all_nodes() {
161 for label in node.labels {
162 labels.insert(label);
163 }
164 }
165 labels.into_iter().collect()
166 }
167
168 fn all_relationship_types(&self) -> Vec<String> {
169 let mut types = BTreeSet::new();
170 for rel in self.all_relationships() {
171 types.insert(rel.rel_type);
172 }
173 types.into_iter().collect()
174 }
175
176 fn all_node_property_keys(&self) -> Vec<String> {
177 let mut keys = BTreeSet::new();
178 for node in self.all_nodes() {
179 for key in node.properties.keys() {
180 keys.insert(key.clone());
181 }
182 }
183 keys.into_iter().collect()
184 }
185
186 fn all_relationship_property_keys(&self) -> Vec<String> {
187 let mut keys = BTreeSet::new();
188 for rel in self.all_relationships() {
189 for key in rel.properties.keys() {
190 keys.insert(key.clone());
191 }
192 }
193 keys.into_iter().collect()
194 }
195
196 fn all_property_keys(&self) -> Vec<String> {
197 let mut keys = BTreeSet::new();
198
199 for key in self.all_node_property_keys() {
200 keys.insert(key);
201 }
202
203 for key in self.all_relationship_property_keys() {
204 keys.insert(key);
205 }
206
207 keys.into_iter().collect()
208 }
209
210 fn label_property_keys(&self, label: &str) -> Vec<String> {
211 let mut keys = BTreeSet::new();
212 for node in self.nodes_by_label(label) {
213 for key in node.properties.keys() {
214 keys.insert(key.clone());
215 }
216 }
217 keys.into_iter().collect()
218 }
219
220 fn rel_type_property_keys(&self, rel_type: &str) -> Vec<String> {
221 let mut keys = BTreeSet::new();
222 for rel in self.relationships_by_type(rel_type) {
223 for key in rel.properties.keys() {
224 keys.insert(key.clone());
225 }
226 }
227 keys.into_iter().collect()
228 }
229
230 fn has_label_name(&self, label: &str) -> bool {
231 self.all_labels().iter().any(|l| l == label)
232 }
233
234 fn has_relationship_type_name(&self, rel_type: &str) -> bool {
235 self.all_relationship_types().iter().any(|t| t == rel_type)
236 }
237
238 fn has_property_key(&self, key: &str) -> bool {
239 self.all_property_keys().iter().any(|k| k == key)
240 }
241
242 fn label_has_property_key(&self, label: &str, key: &str) -> bool {
243 self.nodes_by_label(label)
244 .into_iter()
245 .any(|n| n.properties.contains_key(key))
246 }
247
248 fn rel_type_has_property_key(&self, rel_type: &str, key: &str) -> bool {
249 self.relationships_by_type(rel_type)
250 .into_iter()
251 .any(|r| r.properties.contains_key(key))
252 }
253
254 fn node_has_label(&self, node_id: NodeId, label: &str) -> bool {
257 self.node_ref(node_id)
258 .map(|n| n.labels.iter().any(|l| l == label))
259 .unwrap_or(false)
260 }
261
262 fn node_labels(&self, node_id: NodeId) -> Option<Vec<String>> {
263 self.node_ref(node_id).map(|n| n.labels.clone())
264 }
265
266 fn node_properties(&self, node_id: NodeId) -> Option<Properties> {
267 self.node_ref(node_id).map(|n| n.properties.clone())
268 }
269
270 fn node_property(&self, node_id: NodeId, key: &str) -> Option<PropertyValue> {
271 self.node_ref(node_id)
272 .and_then(|n| n.properties.get(key).cloned())
273 }
274
275 fn relationship_type(&self, rel_id: RelationshipId) -> Option<String> {
276 self.relationship_ref(rel_id).map(|r| r.rel_type.clone())
277 }
278
279 fn relationship_properties(&self, rel_id: RelationshipId) -> Option<Properties> {
280 self.relationship_ref(rel_id).map(|r| r.properties.clone())
281 }
282
283 fn relationship_property(&self, rel_id: RelationshipId, key: &str) -> Option<PropertyValue> {
284 self.relationship_ref(rel_id)
285 .and_then(|r| r.properties.get(key).cloned())
286 }
287
288 fn relationship_endpoints(&self, rel_id: RelationshipId) -> Option<(NodeId, NodeId)> {
291 self.relationship_ref(rel_id).map(|r| (r.src, r.dst))
292 }
293
294 fn relationship_source(&self, rel_id: RelationshipId) -> Option<NodeId> {
295 self.relationship_ref(rel_id).map(|r| r.src)
296 }
297
298 fn relationship_target(&self, rel_id: RelationshipId) -> Option<NodeId> {
299 self.relationship_ref(rel_id).map(|r| r.dst)
300 }
301
302 fn other_node(&self, rel_id: RelationshipId, node_id: NodeId) -> Option<NodeId> {
303 self.relationship_ref(rel_id)
304 .and_then(|r| r.other_node(node_id))
305 }
306
307 fn outgoing_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord>;
310 fn incoming_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord>;
311
312 fn relationships_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipRecord> {
313 match direction {
314 Direction::Right => self.outgoing_relationships(node_id),
315 Direction::Left => self.incoming_relationships(node_id),
316 Direction::Undirected => {
317 let mut rels = self.outgoing_relationships(node_id);
318 rels.extend(self.incoming_relationships(node_id));
319 rels
320 }
321 }
322 }
323
324 fn relationship_ids_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipId> {
327 self.expand_ids(node_id, direction, &[])
328 .into_iter()
329 .map(|(rel_id, _)| rel_id)
330 .collect()
331 }
332
333 fn expand(
334 &self,
335 node_id: NodeId,
336 direction: Direction,
337 types: &[String],
338 ) -> Vec<(RelationshipRecord, NodeRecord)> {
339 let rels = self.relationships_of(node_id, direction);
340
341 rels.into_iter()
342 .filter(|r| types.is_empty() || types.iter().any(|t| t == &r.rel_type))
343 .filter_map(|r| {
344 let other_id = r.other_node(node_id)?;
345 let other = self.node(other_id)?;
346 Some((r, other))
347 })
348 .collect()
349 }
350
351 fn expand_ids(
357 &self,
358 node_id: NodeId,
359 direction: Direction,
360 types: &[String],
361 ) -> Vec<(RelationshipId, NodeId)> {
362 self.expand(node_id, direction, types)
363 .into_iter()
364 .map(|(r, n)| (r.id, n.id))
365 .collect()
366 }
367
368 fn expand_detailed(
369 &self,
370 node_id: NodeId,
371 direction: Direction,
372 types: &[String],
373 ) -> Vec<ExpandedRelationship> {
374 self.expand(node_id, direction, types)
375 .into_iter()
376 .map(|(relationship, other_node)| ExpandedRelationship {
377 relationship,
378 other_node,
379 })
380 .collect()
381 }
382
383 fn neighbors(
384 &self,
385 node_id: NodeId,
386 direction: Direction,
387 types: &[String],
388 ) -> Vec<NodeRecord> {
389 self.expand(node_id, direction, types)
390 .into_iter()
391 .map(|(_, node)| node)
392 .collect()
393 }
394
395 fn degree(&self, node_id: NodeId, direction: Direction) -> usize {
396 match direction {
397 Direction::Left => self.incoming_relationships(node_id).len(),
398 Direction::Right => self.outgoing_relationships(node_id).len(),
399 Direction::Undirected => {
400 self.outgoing_relationships(node_id).len()
401 + self.incoming_relationships(node_id).len()
402 }
403 }
404 }
405
406 fn is_isolated(&self, node_id: NodeId) -> bool {
407 self.degree(node_id, Direction::Undirected) == 0
408 }
409
410 fn find_nodes_by_property(
413 &self,
414 label: Option<&str>,
415 key: &str,
416 value: &PropertyValue,
417 ) -> Vec<NodeRecord> {
418 let ids = match label {
419 Some(label) => self.node_ids_by_label(label),
420 None => self.all_node_ids(),
421 };
422
423 ids.into_iter()
424 .filter_map(|id| {
425 let n = self.node_ref(id)?;
426 if n.properties.get(key) == Some(value) {
427 Some(n.clone())
428 } else {
429 None
430 }
431 })
432 .collect()
433 }
434
435 fn find_relationships_by_property(
436 &self,
437 rel_type: Option<&str>,
438 key: &str,
439 value: &PropertyValue,
440 ) -> Vec<RelationshipRecord> {
441 let ids = match rel_type {
442 Some(rel_type) => self.rel_ids_by_type(rel_type),
443 None => self.all_rel_ids(),
444 };
445
446 ids.into_iter()
447 .filter_map(|id| {
448 let r = self.relationship_ref(id)?;
449 if r.properties.get(key) == Some(value) {
450 Some(r.clone())
451 } else {
452 None
453 }
454 })
455 .collect()
456 }
457
458 fn node_exists_with_label_and_property(
459 &self,
460 label: &str,
461 key: &str,
462 value: &PropertyValue,
463 ) -> bool {
464 !self
465 .find_nodes_by_property(Some(label), key, value)
466 .is_empty()
467 }
468
469 fn relationship_exists_with_type_and_property(
470 &self,
471 rel_type: &str,
472 key: &str,
473 value: &PropertyValue,
474 ) -> bool {
475 !self
476 .find_relationships_by_property(Some(rel_type), key, value)
477 .is_empty()
478 }
479}
480
481pub trait GraphStorageMut: GraphStorage {
482 fn create_node(&mut self, labels: Vec<String>, properties: Properties) -> NodeRecord;
485
486 fn create_relationship(
487 &mut self,
488 src: NodeId,
489 dst: NodeId,
490 rel_type: &str,
491 properties: Properties,
492 ) -> Option<RelationshipRecord>;
493
494 fn set_node_property(&mut self, node_id: NodeId, key: String, value: PropertyValue) -> bool;
497
498 fn remove_node_property(&mut self, node_id: NodeId, key: &str) -> bool;
499
500 fn replace_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool {
501 if !self.has_node(node_id) {
502 return false;
503 }
504
505 let existing_keys = match self.node_properties(node_id) {
506 Some(props) => props.into_keys().collect::<Vec<_>>(),
507 None => return false,
508 };
509
510 for key in existing_keys {
511 self.remove_node_property(node_id, &key);
512 }
513
514 for (k, v) in properties {
515 self.set_node_property(node_id, k, v);
516 }
517
518 true
519 }
520
521 fn merge_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool {
522 if !self.has_node(node_id) {
523 return false;
524 }
525
526 for (k, v) in properties {
527 self.set_node_property(node_id, k, v);
528 }
529
530 true
531 }
532
533 fn add_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
534 fn remove_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
535
536 fn set_node_labels(&mut self, node_id: NodeId, labels: Vec<String>) -> bool {
537 if !self.has_node(node_id) {
538 return false;
539 }
540
541 let current = match self.node_labels(node_id) {
542 Some(labels) => labels,
543 None => return false,
544 };
545
546 for label in ¤t {
547 self.remove_node_label(node_id, label);
548 }
549
550 for label in &labels {
551 self.add_node_label(node_id, label);
552 }
553
554 true
555 }
556
557 fn set_relationship_property(
560 &mut self,
561 rel_id: RelationshipId,
562 key: String,
563 value: PropertyValue,
564 ) -> bool;
565
566 fn remove_relationship_property(&mut self, rel_id: RelationshipId, key: &str) -> bool;
567
568 fn replace_relationship_properties(
569 &mut self,
570 rel_id: RelationshipId,
571 properties: Properties,
572 ) -> bool {
573 if !self.has_relationship(rel_id) {
574 return false;
575 }
576
577 let existing_keys = match self.relationship_properties(rel_id) {
578 Some(props) => props.into_keys().collect::<Vec<_>>(),
579 None => return false,
580 };
581
582 for key in existing_keys {
583 self.remove_relationship_property(rel_id, &key);
584 }
585
586 for (k, v) in properties {
587 self.set_relationship_property(rel_id, k, v);
588 }
589
590 true
591 }
592
593 fn merge_relationship_properties(
594 &mut self,
595 rel_id: RelationshipId,
596 properties: Properties,
597 ) -> bool {
598 if !self.has_relationship(rel_id) {
599 return false;
600 }
601
602 for (k, v) in properties {
603 self.set_relationship_property(rel_id, k, v);
604 }
605
606 true
607 }
608
609 fn delete_relationship(&mut self, rel_id: RelationshipId) -> bool;
612
613 fn delete_node(&mut self, node_id: NodeId) -> bool;
615
616 fn detach_delete_node(&mut self, node_id: NodeId) -> bool;
618
619 fn delete_relationships_of(&mut self, node_id: NodeId, direction: Direction) -> usize {
620 let rel_ids = self.relationship_ids_of(node_id, direction);
621
622 let mut deleted = 0;
623 for rel_id in rel_ids {
624 if self.delete_relationship(rel_id) {
625 deleted += 1;
626 }
627 }
628 deleted
629 }
630
631 fn get_or_create_node(
634 &mut self,
635 labels: Vec<String>,
636 match_key: &str,
637 match_value: &PropertyValue,
638 init_properties: Properties,
639 ) -> NodeRecord {
640 for label in &labels {
641 let matches = self.find_nodes_by_property(Some(label), match_key, match_value);
642 if let Some(node) = matches.into_iter().next() {
643 return node;
644 }
645 }
646
647 self.create_node(labels, init_properties)
648 }
649}