1use hedl_core::Value;
55use std::collections::BTreeMap;
56
57#[derive(Debug, Clone)]
105pub struct HeaderInfo {
106 pub version: (u32, u32),
108 pub structs: BTreeMap<String, Vec<String>>,
110 pub aliases: BTreeMap<String, String>,
112 pub nests: BTreeMap<String, String>,
114}
115
116impl HeaderInfo {
117 pub fn new() -> Self {
119 Self {
120 version: (1, 0),
121 structs: BTreeMap::new(),
122 aliases: BTreeMap::new(),
123 nests: BTreeMap::new(),
124 }
125 }
126
127 #[inline]
129 pub fn get_schema(&self, type_name: &str) -> Option<&Vec<String>> {
130 self.structs.get(type_name)
131 }
132
133 #[inline]
135 pub fn get_child_type(&self, parent_type: &str) -> Option<&String> {
136 self.nests.get(parent_type)
137 }
138}
139
140impl Default for HeaderInfo {
141 fn default() -> Self {
142 Self::new()
143 }
144}
145
146#[derive(Debug, Clone)]
223pub struct NodeInfo {
224 pub type_name: String,
226 pub id: String,
228 pub fields: Vec<Value>,
230 pub depth: usize,
232 pub parent_id: Option<String>,
234 pub parent_type: Option<String>,
236 pub line: usize,
238}
239
240impl NodeInfo {
241 pub fn new(
243 type_name: String,
244 id: String,
245 fields: Vec<Value>,
246 depth: usize,
247 line: usize,
248 ) -> Self {
249 Self {
250 type_name,
251 id,
252 fields,
253 depth,
254 parent_id: None,
255 parent_type: None,
256 line,
257 }
258 }
259
260 pub fn with_parent(mut self, parent_type: String, parent_id: String) -> Self {
262 self.parent_type = Some(parent_type);
263 self.parent_id = Some(parent_id);
264 self
265 }
266
267 #[inline]
269 pub fn get_field(&self, index: usize) -> Option<&Value> {
270 self.fields.get(index)
271 }
272
273 #[inline]
275 pub fn is_nested(&self) -> bool {
276 self.depth > 0 || self.parent_id.is_some()
277 }
278}
279
280#[derive(Debug, Clone)]
282pub enum NodeEvent {
283 Header(HeaderInfo),
285
286 ListStart {
288 key: String,
290 type_name: String,
292 schema: Vec<String>,
294 line: usize,
296 },
297
298 Node(NodeInfo),
300
301 ListEnd {
303 key: String,
305 type_name: String,
307 count: usize,
309 },
310
311 Scalar {
313 key: String,
315 value: Value,
317 line: usize,
319 },
320
321 ObjectStart {
323 key: String,
325 line: usize,
327 },
328
329 ObjectEnd {
331 key: String,
333 },
334
335 EndOfDocument,
337}
338
339impl NodeEvent {
340 #[inline]
342 pub fn is_node(&self) -> bool {
343 matches!(self, Self::Node(_))
344 }
345
346 #[inline]
348 pub fn as_node(&self) -> Option<&NodeInfo> {
349 match self {
350 Self::Node(info) => Some(info),
351 _ => None,
352 }
353 }
354
355 #[inline]
357 pub fn line(&self) -> Option<usize> {
358 match self {
359 Self::Header(_) => Some(1),
360 Self::ListStart { line, .. } => Some(*line),
361 Self::Node(info) => Some(info.line),
362 Self::Scalar { line, .. } => Some(*line),
363 Self::ObjectStart { line, .. } => Some(*line),
364 _ => None,
365 }
366 }
367}
368
369#[cfg(test)]
370mod tests {
371 use super::*;
372
373 #[test]
376 fn test_header_info_new() {
377 let header = HeaderInfo::new();
378 assert_eq!(header.version, (1, 0));
379 assert!(header.structs.is_empty());
380 assert!(header.aliases.is_empty());
381 assert!(header.nests.is_empty());
382 }
383
384 #[test]
385 fn test_header_info_default() {
386 let header = HeaderInfo::default();
387 assert_eq!(header.version, (1, 0));
388 assert!(header.structs.is_empty());
389 }
390
391 #[test]
392 fn test_header_info_get_schema() {
393 let mut header = HeaderInfo::new();
394 header.structs.insert(
395 "User".to_string(),
396 vec!["id".to_string(), "name".to_string()],
397 );
398
399 assert_eq!(
400 header.get_schema("User"),
401 Some(&vec!["id".to_string(), "name".to_string()])
402 );
403 assert_eq!(header.get_schema("Unknown"), None);
404 }
405
406 #[test]
407 fn test_header_info_get_child_type() {
408 let mut header = HeaderInfo::new();
409 header.nests.insert("User".to_string(), "Order".to_string());
410
411 assert_eq!(header.get_child_type("User"), Some(&"Order".to_string()));
412 assert_eq!(header.get_child_type("Product"), None);
413 }
414
415 #[test]
416 fn test_header_info_multiple_structs() {
417 let mut header = HeaderInfo::new();
418 header
419 .structs
420 .insert("User".to_string(), vec!["id".to_string()]);
421 header.structs.insert(
422 "Product".to_string(),
423 vec!["id".to_string(), "price".to_string()],
424 );
425 header.structs.insert(
426 "Order".to_string(),
427 vec!["id".to_string(), "user".to_string(), "product".to_string()],
428 );
429
430 assert_eq!(header.structs.len(), 3);
431 assert_eq!(header.get_schema("User").unwrap().len(), 1);
432 assert_eq!(header.get_schema("Product").unwrap().len(), 2);
433 assert_eq!(header.get_schema("Order").unwrap().len(), 3);
434 }
435
436 #[test]
437 fn test_header_info_multiple_aliases() {
438 let mut header = HeaderInfo::new();
439 header
440 .aliases
441 .insert("active".to_string(), "Active".to_string());
442 header
443 .aliases
444 .insert("inactive".to_string(), "Inactive".to_string());
445
446 assert_eq!(header.aliases.len(), 2);
447 assert_eq!(header.aliases.get("active"), Some(&"Active".to_string()));
448 }
449
450 #[test]
451 fn test_header_info_multiple_nests() {
452 let mut header = HeaderInfo::new();
453 header.nests.insert("User".to_string(), "Order".to_string());
454 header
455 .nests
456 .insert("Order".to_string(), "LineItem".to_string());
457
458 assert_eq!(header.nests.len(), 2);
459 assert_eq!(header.get_child_type("User"), Some(&"Order".to_string()));
460 assert_eq!(
461 header.get_child_type("Order"),
462 Some(&"LineItem".to_string())
463 );
464 }
465
466 #[test]
467 fn test_header_info_clone() {
468 let mut header = HeaderInfo::new();
469 header.version = (2, 1);
470 header
471 .structs
472 .insert("Test".to_string(), vec!["col".to_string()]);
473
474 let cloned = header.clone();
475 assert_eq!(cloned.version, (2, 1));
476 assert_eq!(cloned.structs.get("Test"), Some(&vec!["col".to_string()]));
477 }
478
479 #[test]
480 fn test_header_info_debug() {
481 let header = HeaderInfo::new();
482 let debug = format!("{:?}", header);
483 assert!(debug.contains("HeaderInfo"));
484 assert!(debug.contains("version"));
485 }
486
487 #[test]
490 fn test_node_info_new() {
491 let node = NodeInfo::new(
492 "User".to_string(),
493 "alice".to_string(),
494 vec![
495 Value::String("alice".to_string()),
496 Value::String("Alice".to_string()),
497 ],
498 0,
499 10,
500 );
501
502 assert_eq!(node.type_name, "User");
503 assert_eq!(node.id, "alice");
504 assert_eq!(node.fields.len(), 2);
505 assert_eq!(node.depth, 0);
506 assert_eq!(node.line, 10);
507 assert_eq!(node.parent_id, None);
508 assert_eq!(node.parent_type, None);
509 }
510
511 #[test]
512 fn test_node_info_with_parent() {
513 let node = NodeInfo::new(
514 "Order".to_string(),
515 "order1".to_string(),
516 vec![Value::String("order1".to_string())],
517 1,
518 15,
519 )
520 .with_parent("User".to_string(), "alice".to_string());
521
522 assert_eq!(node.parent_type, Some("User".to_string()));
523 assert_eq!(node.parent_id, Some("alice".to_string()));
524 }
525
526 #[test]
527 fn test_node_info_get_field() {
528 let node = NodeInfo::new(
529 "Data".to_string(),
530 "row1".to_string(),
531 vec![
532 Value::String("row1".to_string()),
533 Value::Int(42),
534 Value::Bool(true),
535 ],
536 0,
537 5,
538 );
539
540 assert_eq!(node.get_field(0), Some(&Value::String("row1".to_string())));
541 assert_eq!(node.get_field(1), Some(&Value::Int(42)));
542 assert_eq!(node.get_field(2), Some(&Value::Bool(true)));
543 assert_eq!(node.get_field(3), None);
544 assert_eq!(node.get_field(100), None);
545 }
546
547 #[test]
548 fn test_node_info_is_nested_by_depth() {
549 let nested = NodeInfo::new("Child".to_string(), "c1".to_string(), vec![], 1, 10);
550 assert!(nested.is_nested());
551
552 let top_level = NodeInfo::new("Parent".to_string(), "p1".to_string(), vec![], 0, 5);
553 assert!(!top_level.is_nested());
554 }
555
556 #[test]
557 fn test_node_info_is_nested_by_parent() {
558 let with_parent = NodeInfo::new("Child".to_string(), "c1".to_string(), vec![], 0, 10)
559 .with_parent("Parent".to_string(), "p1".to_string());
560 assert!(with_parent.is_nested());
561 }
562
563 #[test]
564 fn test_node_info_clone() {
565 let node = NodeInfo::new(
566 "User".to_string(),
567 "alice".to_string(),
568 vec![Value::String("alice".to_string())],
569 0,
570 1,
571 );
572 let cloned = node.clone();
573
574 assert_eq!(cloned.type_name, "User");
575 assert_eq!(cloned.id, "alice");
576 }
577
578 #[test]
579 fn test_node_info_debug() {
580 let node = NodeInfo::new("User".to_string(), "alice".to_string(), vec![], 0, 1);
581 let debug = format!("{:?}", node);
582 assert!(debug.contains("NodeInfo"));
583 assert!(debug.contains("User"));
584 assert!(debug.contains("alice"));
585 }
586
587 #[test]
588 fn test_node_info_empty_fields() {
589 let node = NodeInfo::new("Empty".to_string(), "e1".to_string(), vec![], 0, 1);
590 assert!(node.fields.is_empty());
591 assert_eq!(node.get_field(0), None);
592 }
593
594 #[test]
595 fn test_node_info_all_value_types() {
596 let node = NodeInfo::new(
597 "AllTypes".to_string(),
598 "test".to_string(),
599 vec![
600 Value::Null,
601 Value::Bool(true),
602 Value::Int(-42),
603 Value::Float(3.5),
604 Value::String("hello".to_string()),
605 ],
606 0,
607 1,
608 );
609
610 assert_eq!(node.get_field(0), Some(&Value::Null));
611 assert_eq!(node.get_field(1), Some(&Value::Bool(true)));
612 assert_eq!(node.get_field(2), Some(&Value::Int(-42)));
613 assert_eq!(node.get_field(3), Some(&Value::Float(3.5)));
614 assert_eq!(node.get_field(4), Some(&Value::String("hello".to_string())));
615 }
616
617 #[test]
620 fn test_node_event_is_node() {
621 let node_info = NodeInfo::new("User".to_string(), "a".to_string(), vec![], 0, 1);
622 let node_event = NodeEvent::Node(node_info);
623 assert!(node_event.is_node());
624
625 let header_event = NodeEvent::Header(HeaderInfo::new());
626 assert!(!header_event.is_node());
627
628 let list_start = NodeEvent::ListStart {
629 key: "users".to_string(),
630 type_name: "User".to_string(),
631 schema: vec![],
632 line: 1,
633 };
634 assert!(!list_start.is_node());
635 }
636
637 #[test]
638 fn test_node_event_as_node() {
639 let node_info = NodeInfo::new("User".to_string(), "alice".to_string(), vec![], 0, 5);
640 let node_event = NodeEvent::Node(node_info);
641
642 let extracted = node_event.as_node().unwrap();
643 assert_eq!(extracted.id, "alice");
644
645 let header_event = NodeEvent::Header(HeaderInfo::new());
646 assert!(header_event.as_node().is_none());
647 }
648
649 #[test]
650 fn test_node_event_line_header() {
651 let event = NodeEvent::Header(HeaderInfo::new());
652 assert_eq!(event.line(), Some(1));
653 }
654
655 #[test]
656 fn test_node_event_line_list_start() {
657 let event = NodeEvent::ListStart {
658 key: "users".to_string(),
659 type_name: "User".to_string(),
660 schema: vec![],
661 line: 42,
662 };
663 assert_eq!(event.line(), Some(42));
664 }
665
666 #[test]
667 fn test_node_event_line_node() {
668 let node = NodeInfo::new("User".to_string(), "a".to_string(), vec![], 0, 100);
669 let event = NodeEvent::Node(node);
670 assert_eq!(event.line(), Some(100));
671 }
672
673 #[test]
674 fn test_node_event_line_scalar() {
675 let event = NodeEvent::Scalar {
676 key: "name".to_string(),
677 value: Value::String("test".to_string()),
678 line: 25,
679 };
680 assert_eq!(event.line(), Some(25));
681 }
682
683 #[test]
684 fn test_node_event_line_object_start() {
685 let event = NodeEvent::ObjectStart {
686 key: "config".to_string(),
687 line: 50,
688 };
689 assert_eq!(event.line(), Some(50));
690 }
691
692 #[test]
693 fn test_node_event_line_list_end() {
694 let event = NodeEvent::ListEnd {
695 key: "users".to_string(),
696 type_name: "User".to_string(),
697 count: 10,
698 };
699 assert_eq!(event.line(), None);
700 }
701
702 #[test]
703 fn test_node_event_line_object_end() {
704 let event = NodeEvent::ObjectEnd {
705 key: "config".to_string(),
706 };
707 assert_eq!(event.line(), None);
708 }
709
710 #[test]
711 fn test_node_event_line_end_of_document() {
712 let event = NodeEvent::EndOfDocument;
713 assert_eq!(event.line(), None);
714 }
715
716 #[test]
717 fn test_node_event_clone() {
718 let event = NodeEvent::Scalar {
719 key: "key".to_string(),
720 value: Value::Int(42),
721 line: 10,
722 };
723 let cloned = event.clone();
724
725 if let NodeEvent::Scalar { key, value, line } = cloned {
726 assert_eq!(key, "key");
727 assert_eq!(value, Value::Int(42));
728 assert_eq!(line, 10);
729 } else {
730 panic!("Expected Scalar");
731 }
732 }
733
734 #[test]
735 fn test_node_event_debug() {
736 let event = NodeEvent::EndOfDocument;
737 let debug = format!("{:?}", event);
738 assert!(debug.contains("EndOfDocument"));
739 }
740
741 #[test]
742 fn test_node_event_list_start_fields() {
743 let event = NodeEvent::ListStart {
744 key: "users".to_string(),
745 type_name: "User".to_string(),
746 schema: vec!["id".to_string(), "name".to_string()],
747 line: 5,
748 };
749
750 if let NodeEvent::ListStart {
751 key,
752 type_name,
753 schema,
754 line,
755 } = event
756 {
757 assert_eq!(key, "users");
758 assert_eq!(type_name, "User");
759 assert_eq!(schema, vec!["id".to_string(), "name".to_string()]);
760 assert_eq!(line, 5);
761 }
762 }
763
764 #[test]
765 fn test_node_event_list_end_fields() {
766 let event = NodeEvent::ListEnd {
767 key: "products".to_string(),
768 type_name: "Product".to_string(),
769 count: 100,
770 };
771
772 if let NodeEvent::ListEnd {
773 key,
774 type_name,
775 count,
776 } = event
777 {
778 assert_eq!(key, "products");
779 assert_eq!(type_name, "Product");
780 assert_eq!(count, 100);
781 }
782 }
783
784 #[test]
785 fn test_node_event_scalar_all_value_types() {
786 let events = [
787 NodeEvent::Scalar {
788 key: "null".to_string(),
789 value: Value::Null,
790 line: 1,
791 },
792 NodeEvent::Scalar {
793 key: "bool".to_string(),
794 value: Value::Bool(true),
795 line: 2,
796 },
797 NodeEvent::Scalar {
798 key: "int".to_string(),
799 value: Value::Int(-100),
800 line: 3,
801 },
802 NodeEvent::Scalar {
803 key: "float".to_string(),
804 value: Value::Float(2.75),
805 line: 4,
806 },
807 NodeEvent::Scalar {
808 key: "string".to_string(),
809 value: Value::String("text".to_string()),
810 line: 5,
811 },
812 ];
813
814 for (i, event) in events.iter().enumerate() {
815 assert_eq!(event.line(), Some(i + 1));
816 assert!(!event.is_node());
817 }
818 }
819}