1use crate::graph::{Edge, EdgeId, EdgeType, GraphStore, Node, NodeId, PropertyValue};
42use std::collections::HashMap;
43use std::hash::{Hash, Hasher};
44
45#[derive(Debug, Clone)]
47pub struct Record {
48 bindings: HashMap<String, Value>,
50}
51
52#[derive(Debug, Clone)]
74pub enum Value {
75 Node(NodeId, Node),
77 NodeRef(NodeId),
79 Edge(EdgeId, Edge),
81 EdgeRef(EdgeId, NodeId, NodeId, EdgeType),
83 Property(PropertyValue),
85 Path {
87 nodes: Vec<NodeId>,
88 edges: Vec<EdgeId>,
89 },
90 Null,
92}
93
94impl PartialEq for Value {
96 fn eq(&self, other: &Self) -> bool {
97 match (self, other) {
98 (Value::Node(id1, _), Value::Node(id2, _)) => id1 == id2,
100 (Value::NodeRef(id1), Value::NodeRef(id2)) => id1 == id2,
101 (Value::Node(id1, _), Value::NodeRef(id2))
102 | (Value::NodeRef(id2), Value::Node(id1, _)) => id1 == id2,
103 (Value::Edge(id1, _), Value::Edge(id2, _)) => id1 == id2,
105 (Value::EdgeRef(id1, ..), Value::EdgeRef(id2, ..)) => id1 == id2,
106 (Value::Edge(id1, _), Value::EdgeRef(id2, ..))
107 | (Value::EdgeRef(id2, ..), Value::Edge(id1, _)) => id1 == id2,
108 (Value::Property(p1), Value::Property(p2)) => p1 == p2,
110 (
112 Value::Path {
113 nodes: n1,
114 edges: e1,
115 },
116 Value::Path {
117 nodes: n2,
118 edges: e2,
119 },
120 ) => n1 == n2 && e1 == e2,
121 (Value::Null, Value::Null) => true,
122 _ => false,
123 }
124 }
125}
126
127impl Eq for Value {}
128
129impl Hash for Value {
130 fn hash<H: Hasher>(&self, state: &mut H) {
131 match self {
133 Value::Node(id, _) | Value::NodeRef(id) => {
134 0u8.hash(state);
135 id.hash(state);
136 }
137 Value::Edge(id, _) | Value::EdgeRef(id, ..) => {
138 1u8.hash(state);
139 id.hash(state);
140 }
141 Value::Property(p) => {
142 2u8.hash(state);
143 p.hash(state);
144 }
145 Value::Path { nodes, edges } => {
146 3u8.hash(state);
147 nodes.hash(state);
148 edges.hash(state);
149 }
150 Value::Null => {
151 4u8.hash(state);
152 }
153 }
154 }
155}
156
157impl Record {
158 pub fn new() -> Self {
160 Self {
161 bindings: HashMap::new(),
162 }
163 }
164
165 pub fn bind(&mut self, variable: String, value: Value) {
167 self.bindings.insert(variable, value);
168 }
169
170 pub fn get(&self, variable: &str) -> Option<&Value> {
172 self.bindings.get(variable)
173 }
174
175 pub fn bindings(&self) -> &HashMap<String, Value> {
177 &self.bindings
178 }
179
180 pub fn has(&self, variable: &str) -> bool {
182 self.bindings.contains_key(variable)
183 }
184
185 pub fn merge(&mut self, other: Record) {
187 self.bindings.extend(other.bindings);
188 }
189
190 pub fn project(&self, variables: &[String]) -> Record {
192 let mut new_record = Record::new();
193 for var in variables {
194 if let Some(value) = self.bindings.get(var) {
195 new_record.bind(var.clone(), value.clone());
196 }
197 }
198 new_record
199 }
200}
201
202impl Default for Record {
203 fn default() -> Self {
204 Self::new()
205 }
206}
207
208impl Value {
209 pub fn as_node(&self) -> Option<(NodeId, &Node)> {
211 match self {
212 Value::Node(id, node) => Some((*id, node)),
213 _ => None,
214 }
215 }
216
217 pub fn as_edge(&self) -> Option<(EdgeId, &Edge)> {
219 match self {
220 Value::Edge(id, edge) => Some((*id, edge)),
221 _ => None,
222 }
223 }
224
225 pub fn as_property(&self) -> Option<&PropertyValue> {
227 match self {
228 Value::Property(prop) => Some(prop),
229 _ => None,
230 }
231 }
232
233 pub fn is_null(&self) -> bool {
235 matches!(self, Value::Null)
236 }
237
238 pub fn node_id(&self) -> Option<NodeId> {
240 match self {
241 Value::Node(id, _) | Value::NodeRef(id) => Some(*id),
242 _ => None,
243 }
244 }
245
246 pub fn edge_id(&self) -> Option<EdgeId> {
248 match self {
249 Value::Edge(id, _) => Some(*id),
250 Value::EdgeRef(id, ..) => Some(*id),
251 _ => None,
252 }
253 }
254
255 pub fn edge_endpoints(&self) -> Option<(NodeId, NodeId)> {
257 match self {
258 Value::Edge(_, edge) => Some((edge.source, edge.target)),
259 Value::EdgeRef(_, src, tgt, _) => Some((*src, *tgt)),
260 _ => None,
261 }
262 }
263
264 pub fn edge_type(&self) -> Option<&EdgeType> {
266 match self {
267 Value::Edge(_, edge) => Some(&edge.edge_type),
268 Value::EdgeRef(_, _, _, et) => Some(et),
269 _ => None,
270 }
271 }
272
273 pub fn is_node(&self) -> bool {
275 matches!(self, Value::Node(..) | Value::NodeRef(..))
276 }
277
278 pub fn is_edge(&self) -> bool {
280 matches!(self, Value::Edge(..) | Value::EdgeRef(..))
281 }
282
283 pub fn materialize_node(self, store: &GraphStore) -> Self {
286 match self {
287 Value::NodeRef(id) => {
288 if let Some(node) = store.get_node(id) {
289 Value::Node(id, node.clone())
290 } else {
291 Value::Null
292 }
293 }
294 other => other,
295 }
296 }
297
298 pub fn materialize_edge(self, store: &GraphStore) -> Self {
301 match self {
302 Value::EdgeRef(id, ..) => {
303 if let Some(edge) = store.get_edge(id) {
304 Value::Edge(id, edge.clone())
305 } else {
306 Value::Null
307 }
308 }
309 other => other,
310 }
311 }
312
313 pub fn resolve_property(&self, property: &str, store: &GraphStore) -> PropertyValue {
316 match self {
317 Value::Node(id, node) => {
318 let prop = store
319 .node_columns
320 .get_property(id.as_u64() as usize, property);
321 if !prop.is_null() {
322 prop
323 } else {
324 node.get_property(property)
325 .cloned()
326 .unwrap_or(PropertyValue::Null)
327 }
328 }
329 Value::NodeRef(id) => {
330 let prop = store
331 .node_columns
332 .get_property(id.as_u64() as usize, property);
333 if !prop.is_null() {
334 prop
335 } else if let Some(node) = store.get_node(*id) {
336 node.get_property(property)
337 .cloned()
338 .unwrap_or(PropertyValue::Null)
339 } else {
340 PropertyValue::Null
341 }
342 }
343 Value::Edge(id, edge) => {
344 let prop = store
345 .edge_columns
346 .get_property(id.as_u64() as usize, property);
347 if !prop.is_null() {
348 prop
349 } else {
350 edge.get_property(property)
351 .cloned()
352 .unwrap_or(PropertyValue::Null)
353 }
354 }
355 Value::EdgeRef(id, ..) => {
356 let prop = store
357 .edge_columns
358 .get_property(id.as_u64() as usize, property);
359 if !prop.is_null() {
360 prop
361 } else if let Some(edge) = store.get_edge(*id) {
362 edge.get_property(property)
363 .cloned()
364 .unwrap_or(PropertyValue::Null)
365 } else {
366 PropertyValue::Null
367 }
368 }
369 _ => PropertyValue::Null,
370 }
371 }
372}
373
374#[derive(Debug)]
376pub struct RecordBatch {
377 pub records: Vec<Record>,
379 pub columns: Vec<String>,
381}
382
383impl RecordBatch {
384 pub fn new(columns: Vec<String>) -> Self {
386 Self {
387 records: Vec::new(),
388 columns,
389 }
390 }
391
392 pub fn len(&self) -> usize {
394 self.records.len()
395 }
396
397 pub fn is_empty(&self) -> bool {
399 self.records.is_empty()
400 }
401
402 pub fn push(&mut self, record: Record) {
404 self.records.push(record);
405 }
406
407 pub fn get(&self, index: usize) -> Option<&Record> {
409 self.records.get(index)
410 }
411}
412
413#[cfg(test)]
414mod tests {
415 use super::*;
416 use crate::graph::Label;
417
418 #[test]
419 fn test_record_creation() {
420 let record = Record::new();
421 assert_eq!(record.bindings().len(), 0);
422 }
423
424 #[test]
425 fn test_record_binding() {
426 let mut record = Record::new();
427 let node = Node::new(NodeId::new(1), Label::new("Person"));
428
429 record.bind("n".to_string(), Value::Node(NodeId::new(1), node));
430
431 assert!(record.has("n"));
432 assert!(record.get("n").is_some());
433 }
434
435 #[test]
436 fn test_record_merge() {
437 let mut record1 = Record::new();
438 let mut record2 = Record::new();
439
440 record1.bind("a".to_string(), Value::Property(PropertyValue::Integer(1)));
441 record2.bind("b".to_string(), Value::Property(PropertyValue::Integer(2)));
442
443 record1.merge(record2);
444
445 assert!(record1.has("a"));
446 assert!(record1.has("b"));
447 }
448
449 #[test]
450 fn test_record_project() {
451 let mut record = Record::new();
452 record.bind("a".to_string(), Value::Property(PropertyValue::Integer(1)));
453 record.bind("b".to_string(), Value::Property(PropertyValue::Integer(2)));
454 record.bind("c".to_string(), Value::Property(PropertyValue::Integer(3)));
455
456 let projected = record.project(&vec!["a".to_string(), "c".to_string()]);
457
458 assert!(projected.has("a"));
459 assert!(!projected.has("b"));
460 assert!(projected.has("c"));
461 }
462
463 #[test]
464 fn test_value_types() {
465 let node_val = Value::Node(
466 NodeId::new(1),
467 Node::new(NodeId::new(1), Label::new("Test")),
468 );
469 assert!(node_val.as_node().is_some());
470 assert!(node_val.as_edge().is_none());
471
472 let prop_val = Value::Property(PropertyValue::String("test".to_string()));
473 assert!(prop_val.as_property().is_some());
474
475 let null_val = Value::Null;
476 assert!(null_val.is_null());
477 }
478
479 #[test]
480 fn test_record_batch() {
481 let mut batch = RecordBatch::new(vec!["n".to_string(), "m".to_string()]);
482 assert_eq!(batch.len(), 0);
483 assert!(batch.is_empty());
484
485 batch.push(Record::new());
486 assert_eq!(batch.len(), 1);
487 assert!(!batch.is_empty());
488 }
489
490 #[test]
493 fn test_as_edge() {
494 let edge = crate::graph::Edge::new(
495 EdgeId::new(1),
496 NodeId::new(10),
497 NodeId::new(20),
498 crate::graph::EdgeType::new("KNOWS"),
499 );
500 let val = Value::Edge(EdgeId::new(1), edge);
501 let (eid, e) = val.as_edge().unwrap();
502 assert_eq!(eid, EdgeId::new(1));
503 assert_eq!(e.source, NodeId::new(10));
504 assert_eq!(e.target, NodeId::new(20));
505
506 assert!(Value::Null.as_edge().is_none());
508 assert!(Value::NodeRef(NodeId::new(1)).as_edge().is_none());
509 }
510
511 #[test]
512 fn test_node_id() {
513 let node = Node::new(NodeId::new(5), Label::new("Person"));
515 let val = Value::Node(NodeId::new(5), node);
516 assert_eq!(val.node_id(), Some(NodeId::new(5)));
517
518 let val = Value::NodeRef(NodeId::new(7));
520 assert_eq!(val.node_id(), Some(NodeId::new(7)));
521
522 assert!(Value::Null.node_id().is_none());
524 assert!(Value::Property(PropertyValue::Integer(42))
525 .node_id()
526 .is_none());
527 }
528
529 #[test]
530 fn test_edge_id() {
531 let edge = crate::graph::Edge::new(
533 EdgeId::new(3),
534 NodeId::new(1),
535 NodeId::new(2),
536 crate::graph::EdgeType::new("E"),
537 );
538 let val = Value::Edge(EdgeId::new(3), edge);
539 assert_eq!(val.edge_id(), Some(EdgeId::new(3)));
540
541 let val = Value::EdgeRef(
543 EdgeId::new(4),
544 NodeId::new(1),
545 NodeId::new(2),
546 crate::graph::EdgeType::new("E"),
547 );
548 assert_eq!(val.edge_id(), Some(EdgeId::new(4)));
549
550 assert!(Value::Null.edge_id().is_none());
552 }
553
554 #[test]
555 fn test_edge_endpoints() {
556 let edge = crate::graph::Edge::new(
558 EdgeId::new(1),
559 NodeId::new(10),
560 NodeId::new(20),
561 crate::graph::EdgeType::new("E"),
562 );
563 let val = Value::Edge(EdgeId::new(1), edge);
564 assert_eq!(
565 val.edge_endpoints(),
566 Some((NodeId::new(10), NodeId::new(20)))
567 );
568
569 let val = Value::EdgeRef(
571 EdgeId::new(1),
572 NodeId::new(30),
573 NodeId::new(40),
574 crate::graph::EdgeType::new("E"),
575 );
576 assert_eq!(
577 val.edge_endpoints(),
578 Some((NodeId::new(30), NodeId::new(40)))
579 );
580
581 assert!(Value::Null.edge_endpoints().is_none());
583 }
584
585 #[test]
586 fn test_edge_type_accessor() {
587 let edge = crate::graph::Edge::new(
588 EdgeId::new(1),
589 NodeId::new(1),
590 NodeId::new(2),
591 crate::graph::EdgeType::new("KNOWS"),
592 );
593 let val = Value::Edge(EdgeId::new(1), edge);
594 assert_eq!(val.edge_type().unwrap().as_str(), "KNOWS");
595
596 let val = Value::EdgeRef(
597 EdgeId::new(1),
598 NodeId::new(1),
599 NodeId::new(2),
600 crate::graph::EdgeType::new("LIKES"),
601 );
602 assert_eq!(val.edge_type().unwrap().as_str(), "LIKES");
603
604 assert!(Value::Null.edge_type().is_none());
605 }
606
607 #[test]
608 fn test_is_node_is_edge() {
609 let node = Node::new(NodeId::new(1), Label::new("A"));
610 assert!(Value::Node(NodeId::new(1), node).is_node());
611 assert!(Value::NodeRef(NodeId::new(1)).is_node());
612 assert!(!Value::Null.is_node());
613 assert!(!Value::Property(PropertyValue::Integer(1)).is_node());
614
615 let edge = crate::graph::Edge::new(
616 EdgeId::new(1),
617 NodeId::new(1),
618 NodeId::new(2),
619 crate::graph::EdgeType::new("E"),
620 );
621 assert!(Value::Edge(EdgeId::new(1), edge).is_edge());
622 assert!(Value::EdgeRef(
623 EdgeId::new(1),
624 NodeId::new(1),
625 NodeId::new(2),
626 crate::graph::EdgeType::new("E"),
627 )
628 .is_edge());
629 assert!(!Value::Null.is_edge());
630 }
631
632 #[test]
633 fn test_materialize_node() {
634 let mut store = GraphStore::new();
635 let id = store.create_node("Person");
636 store.get_node_mut(id).unwrap().set_property(
637 "name".to_string(),
638 PropertyValue::String("Alice".to_string()),
639 );
640
641 let val = Value::NodeRef(id).materialize_node(&store);
643 match &val {
644 Value::Node(nid, node) => {
645 assert_eq!(*nid, id);
646 assert!(node.labels.contains(&Label::new("Person")));
647 }
648 _ => panic!("Expected Value::Node after materialization"),
649 }
650
651 let node = store.get_node(id).unwrap().clone();
653 let val = Value::Node(id, node).materialize_node(&store);
654 assert!(matches!(val, Value::Node(..)));
655
656 let val = Value::NodeRef(NodeId::new(9999)).materialize_node(&store);
658 assert!(val.is_null());
659
660 let val = Value::Property(PropertyValue::Integer(42)).materialize_node(&store);
662 assert!(matches!(val, Value::Property(..)));
663 }
664
665 #[test]
666 fn test_materialize_edge() {
667 let mut store = GraphStore::new();
668 let a = store.create_node("A");
669 let b = store.create_node("B");
670 let eid = store.create_edge(a, b, "KNOWS").unwrap();
671
672 let val = Value::EdgeRef(eid, a, b, crate::graph::EdgeType::new("KNOWS"))
674 .materialize_edge(&store);
675 match &val {
676 Value::Edge(id, edge) => {
677 assert_eq!(*id, eid);
678 assert_eq!(edge.source, a);
679 assert_eq!(edge.target, b);
680 }
681 _ => panic!("Expected Value::Edge after materialization"),
682 }
683
684 let val = Value::EdgeRef(EdgeId::new(9999), a, b, crate::graph::EdgeType::new("X"))
686 .materialize_edge(&store);
687 assert!(val.is_null());
688
689 let val = Value::Null.materialize_edge(&store);
691 assert!(val.is_null());
692 }
693
694 #[test]
695 fn test_resolve_property_node() {
696 let mut store = GraphStore::new();
697 let id = store.create_node("Person");
698 store.get_node_mut(id).unwrap().set_property(
699 "name".to_string(),
700 PropertyValue::String("Alice".to_string()),
701 );
702
703 let node = store.get_node(id).unwrap().clone();
705 let val = Value::Node(id, node);
706 let prop = val.resolve_property("name", &store);
707 assert_eq!(prop, PropertyValue::String("Alice".to_string()));
708
709 let prop = val.resolve_property("missing", &store);
711 assert_eq!(prop, PropertyValue::Null);
712 }
713
714 #[test]
715 fn test_resolve_property_noderef() {
716 let mut store = GraphStore::new();
717 let id = store.create_node("Person");
718 store
719 .get_node_mut(id)
720 .unwrap()
721 .set_property("age".to_string(), PropertyValue::Integer(30));
722
723 let val = Value::NodeRef(id);
724 let prop = val.resolve_property("age", &store);
725 assert_eq!(prop, PropertyValue::Integer(30));
726
727 let val = Value::NodeRef(NodeId::new(9999));
729 let prop = val.resolve_property("age", &store);
730 assert_eq!(prop, PropertyValue::Null);
731 }
732
733 #[test]
734 fn test_resolve_property_edge() {
735 let mut store = GraphStore::new();
736 let a = store.create_node("A");
737 let b = store.create_node("B");
738
739 let mut props = std::collections::HashMap::new();
740 props.insert("since".to_string(), PropertyValue::Integer(2020));
741 let eid = store
742 .create_edge_with_properties(a, b, "KNOWS", props)
743 .unwrap();
744
745 let edge = store.get_edge(eid).unwrap().clone();
747 let val = Value::Edge(eid, edge);
748 let prop = val.resolve_property("since", &store);
749 assert_eq!(prop, PropertyValue::Integer(2020));
750 }
751
752 #[test]
753 fn test_resolve_property_edgeref() {
754 let mut store = GraphStore::new();
755 let a = store.create_node("A");
756 let b = store.create_node("B");
757
758 let mut props = std::collections::HashMap::new();
759 props.insert("weight".to_string(), PropertyValue::Float(0.5));
760 let eid = store
761 .create_edge_with_properties(a, b, "KNOWS", props)
762 .unwrap();
763
764 let val = Value::EdgeRef(eid, a, b, crate::graph::EdgeType::new("KNOWS"));
765 let prop = val.resolve_property("weight", &store);
766 assert_eq!(prop, PropertyValue::Float(0.5));
767
768 let val = Value::EdgeRef(EdgeId::new(9999), a, b, crate::graph::EdgeType::new("X"));
770 let prop = val.resolve_property("weight", &store);
771 assert_eq!(prop, PropertyValue::Null);
772 }
773
774 #[test]
775 fn test_resolve_property_non_node_edge() {
776 let store = GraphStore::new();
777 let val = Value::Null;
778 assert_eq!(
779 val.resolve_property("anything", &store),
780 PropertyValue::Null
781 );
782
783 let val = Value::Property(PropertyValue::Integer(42));
784 assert_eq!(val.resolve_property("x", &store), PropertyValue::Null);
785 }
786
787 #[test]
788 fn test_record_batch_get() {
789 let mut batch = RecordBatch::new(vec!["n".to_string()]);
790 let mut r1 = Record::new();
791 r1.bind("n".to_string(), Value::Property(PropertyValue::Integer(1)));
792 let mut r2 = Record::new();
793 r2.bind("n".to_string(), Value::Property(PropertyValue::Integer(2)));
794 batch.push(r1);
795 batch.push(r2);
796
797 assert!(batch.get(0).is_some());
798 assert!(batch.get(1).is_some());
799 assert!(batch.get(2).is_none()); let r = batch.get(0).unwrap();
802 assert_eq!(
803 r.get("n").unwrap().as_property(),
804 Some(&PropertyValue::Integer(1))
805 );
806 }
807
808 #[test]
809 fn test_record_bindings() {
810 let mut r = Record::new();
811 r.bind("x".to_string(), Value::Property(PropertyValue::Integer(1)));
812 r.bind("y".to_string(), Value::Null);
813
814 let bindings = r.bindings();
815 assert_eq!(bindings.len(), 2);
816 assert!(bindings.contains_key("x"));
817 assert!(bindings.contains_key("y"));
818 }
819
820 #[test]
821 fn test_record_default() {
822 let r = Record::default();
823 assert_eq!(r.bindings().len(), 0);
824 }
825
826 #[test]
827 fn test_value_partial_eq_cross_variant() {
828 let node = Node::new(NodeId::new(5), Label::new("A"));
830 let v1 = Value::Node(NodeId::new(5), node.clone());
831 let v2 = Value::NodeRef(NodeId::new(5));
832 assert_eq!(v1, v2);
833 assert_eq!(v2, v1);
834
835 let v3 = Value::NodeRef(NodeId::new(6));
837 assert_ne!(v1, v3);
838
839 let edge = crate::graph::Edge::new(
841 EdgeId::new(1),
842 NodeId::new(1),
843 NodeId::new(2),
844 crate::graph::EdgeType::new("E"),
845 );
846 let ev1 = Value::Edge(EdgeId::new(1), edge);
847 let ev2 = Value::EdgeRef(
848 EdgeId::new(1),
849 NodeId::new(1),
850 NodeId::new(2),
851 crate::graph::EdgeType::new("E"),
852 );
853 assert_eq!(ev1, ev2);
854 assert_eq!(ev2, ev1);
855
856 assert_ne!(v1, ev1);
858 assert_ne!(Value::Null, v1);
859
860 let p1 = Value::Path {
862 nodes: vec![NodeId::new(1)],
863 edges: vec![EdgeId::new(1)],
864 };
865 let p2 = Value::Path {
866 nodes: vec![NodeId::new(1)],
867 edges: vec![EdgeId::new(1)],
868 };
869 let p3 = Value::Path {
870 nodes: vec![NodeId::new(2)],
871 edges: vec![EdgeId::new(1)],
872 };
873 assert_eq!(p1, p2);
874 assert_ne!(p1, p3);
875 }
876
877 #[test]
878 fn test_value_hash_cross_variant() {
879 use std::collections::hash_map::DefaultHasher;
880
881 fn hash_value(v: &Value) -> u64 {
882 let mut hasher = DefaultHasher::new();
883 v.hash(&mut hasher);
884 hasher.finish()
885 }
886
887 let node = Node::new(NodeId::new(5), Label::new("A"));
889 let v1 = Value::Node(NodeId::new(5), node);
890 let v2 = Value::NodeRef(NodeId::new(5));
891 assert_eq!(hash_value(&v1), hash_value(&v2));
892
893 let edge = crate::graph::Edge::new(
895 EdgeId::new(3),
896 NodeId::new(1),
897 NodeId::new(2),
898 crate::graph::EdgeType::new("E"),
899 );
900 let ev1 = Value::Edge(EdgeId::new(3), edge);
901 let ev2 = Value::EdgeRef(
902 EdgeId::new(3),
903 NodeId::new(1),
904 NodeId::new(2),
905 crate::graph::EdgeType::new("E"),
906 );
907 assert_eq!(hash_value(&ev1), hash_value(&ev2));
908
909 assert_ne!(hash_value(&v1), hash_value(&ev1));
911 assert_ne!(hash_value(&Value::Null), hash_value(&v1));
912 }
913}