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