1use crate::value::Value;
64use parking_lot::RwLock;
65use std::collections::HashMap;
66
67#[derive(Debug, Clone, PartialEq, Eq)]
73pub struct Mapping {
74 pub property: String,
76 pub column: String,
78 pub type_handler: Option<String>,
80}
81
82impl Mapping {
83 pub fn new(property: impl Into<String>, column: impl Into<String>) -> Self {
85 Self {
86 property: property.into(),
87 column: column.into(),
88 type_handler: None,
89 }
90 }
91
92 pub fn with_handler(
94 property: impl Into<String>,
95 column: impl Into<String>,
96 handler: impl Into<String>,
97 ) -> Self {
98 Self {
99 property: property.into(),
100 column: column.into(),
101 type_handler: Some(handler.into()),
102 }
103 }
104}
105
106#[derive(Debug, Clone, PartialEq, Eq)]
112pub struct NestedAssociation {
113 pub property: String,
115 pub result_map: String,
117 pub column_prefix: Option<String>,
119 pub not_null_column: Option<String>,
121}
122
123impl NestedAssociation {
124 pub fn new(property: impl Into<String>, result_map: impl Into<String>) -> Self {
126 Self {
127 property: property.into(),
128 result_map: result_map.into(),
129 column_prefix: None,
130 not_null_column: None,
131 }
132 }
133
134 pub fn with_prefix(mut self, prefix: impl Into<String>) -> Self {
136 self.column_prefix = Some(prefix.into());
137 self
138 }
139
140 pub fn with_not_null_column(mut self, column: impl Into<String>) -> Self {
142 self.not_null_column = Some(column.into());
143 self
144 }
145}
146
147#[derive(Debug, Clone, PartialEq, Eq)]
153pub struct NestedCollection {
154 pub property: String,
156 pub result_map: String,
158 pub column_prefix: Option<String>,
160 pub not_null_column: Option<String>,
162}
163
164impl NestedCollection {
165 pub fn new(property: impl Into<String>, result_map: impl Into<String>) -> Self {
167 Self {
168 property: property.into(),
169 result_map: result_map.into(),
170 column_prefix: None,
171 not_null_column: None,
172 }
173 }
174
175 pub fn with_prefix(mut self, prefix: impl Into<String>) -> Self {
177 self.column_prefix = Some(prefix.into());
178 self
179 }
180
181 pub fn with_not_null_column(mut self, column: impl Into<String>) -> Self {
183 self.not_null_column = Some(column.into());
184 self
185 }
186}
187
188#[derive(Debug, Clone, PartialEq)]
194pub struct DiscriminatorCase {
195 pub value: Value,
197 pub result_map: String,
199}
200
201impl DiscriminatorCase {
202 pub fn new(value: Value, result_map: impl Into<String>) -> Self {
204 Self {
205 value,
206 result_map: result_map.into(),
207 }
208 }
209}
210
211#[derive(Debug, Clone, PartialEq)]
213pub struct Discriminator {
214 pub column: String,
216 pub cases: Vec<DiscriminatorCase>,
218}
219
220impl Discriminator {
221 pub fn new(column: impl Into<String>) -> Self {
223 Self {
224 column: column.into(),
225 cases: Vec::new(),
226 }
227 }
228
229 pub fn add_case(&mut self, case: DiscriminatorCase) -> &mut Self {
231 self.cases.push(case);
232 self
233 }
234
235 pub fn resolve(&self, value: &Value) -> Option<&str> {
237 for case in &self.cases {
238 if case.value == *value {
239 return Some(&case.result_map);
240 }
241 }
242 None
243 }
244}
245
246#[derive(Debug, Clone, PartialEq)]
252pub struct ResultMap {
253 pub id: String,
255 pub type_name: String,
257 pub id_mappings: Vec<Mapping>,
259 pub result_mappings: Vec<Mapping>,
261 pub associations: Vec<NestedAssociation>,
263 pub collections: Vec<NestedCollection>,
265 pub discriminator: Option<Discriminator>,
267}
268
269impl ResultMap {
270 pub fn new(id: impl Into<String>, type_name: impl Into<String>) -> Self {
272 Self {
273 id: id.into(),
274 type_name: type_name.into(),
275 id_mappings: Vec::new(),
276 result_mappings: Vec::new(),
277 associations: Vec::new(),
278 collections: Vec::new(),
279 discriminator: None,
280 }
281 }
282
283 pub fn add_id_mapping(&mut self, mapping: Mapping) -> &mut Self {
285 self.id_mappings.push(mapping);
286 self
287 }
288
289 pub fn add_result_mapping(&mut self, mapping: Mapping) -> &mut Self {
291 self.result_mappings.push(mapping);
292 self
293 }
294
295 pub fn add_association(&mut self, assoc: NestedAssociation) -> &mut Self {
297 self.associations.push(assoc);
298 self
299 }
300
301 pub fn add_collection(&mut self, coll: NestedCollection) -> &mut Self {
303 self.collections.push(coll);
304 self
305 }
306
307 pub fn set_discriminator(&mut self, disc: Discriminator) -> &mut Self {
309 self.discriminator = Some(disc);
310 self
311 }
312
313 pub fn sub_map_ids(&self) -> Vec<String> {
315 let mut ids = Vec::new();
316 for a in &self.associations {
317 ids.push(a.result_map.clone());
318 }
319 for c in &self.collections {
320 ids.push(c.result_map.clone());
321 }
322 if let Some(d) = &self.discriminator {
323 for case in &d.cases {
324 ids.push(case.result_map.clone());
325 }
326 }
327 ids
328 }
329}
330
331#[derive(Debug, Default)]
337pub struct ResultMapRegistry {
338 maps: RwLock<HashMap<String, ResultMap>>,
339}
340
341impl ResultMapRegistry {
342 pub fn new() -> Self {
344 Self {
345 maps: RwLock::new(HashMap::new()),
346 }
347 }
348
349 pub fn register(&self, map: ResultMap) {
351 let mut maps = self.maps.write();
352 maps.insert(map.id.clone(), map);
353 }
354
355 pub fn get(&self, id: &str) -> Option<ResultMap> {
357 let maps = self.maps.read();
358 maps.get(id).cloned()
359 }
360
361 pub fn contains(&self, id: &str) -> bool {
363 let maps = self.maps.read();
364 maps.contains_key(id)
365 }
366
367 pub fn len(&self) -> usize {
369 let maps = self.maps.read();
370 maps.len()
371 }
372
373 pub fn is_empty(&self) -> bool {
375 self.len() == 0
376 }
377
378 pub fn list_ids(&self) -> Vec<String> {
380 let maps = self.maps.read();
381 maps.keys().cloned().collect()
382 }
383
384 pub fn clear(&self) {
386 let mut maps = self.maps.write();
387 maps.clear();
388 }
389}
390
391#[derive(Debug, Clone, Default)]
397pub struct RowData {
398 columns: HashMap<String, Value>,
399}
400
401impl RowData {
402 pub fn new(columns: HashMap<String, Value>) -> Self {
404 Self { columns }
405 }
406
407 pub fn empty() -> Self {
409 Self {
410 columns: HashMap::new(),
411 }
412 }
413
414 pub fn set(&mut self, column: impl Into<String>, value: Value) {
416 self.columns.insert(column.into(), value);
417 }
418
419 pub fn get(&self, column: &str) -> Option<&Value> {
421 self.columns.get(column)
422 }
423
424 pub fn get_with_prefix(&self, prefix: &str, column: &str) -> Option<&Value> {
428 let full = format!("{}{}", prefix, column);
429 self.columns.get(&full)
430 }
431
432 pub fn is_not_null(&self, column: &str) -> bool {
434 match self.columns.get(column) {
435 Some(Value::Null) | None => false,
436 Some(_) => true,
437 }
438 }
439
440 pub fn len(&self) -> usize {
442 self.columns.len()
443 }
444
445 pub fn is_empty(&self) -> bool {
447 self.columns.is_empty()
448 }
449
450 pub fn column_names(&self) -> Vec<String> {
452 self.columns.keys().cloned().collect()
453 }
454
455 pub fn sorted_columns(&self) -> Vec<(&String, &Value)> {
457 let mut entries: Vec<(&String, &Value)> = self.columns.iter().collect();
458 entries.sort_by(|a, b| a.0.cmp(b.0));
459 entries
460 }
461
462 pub fn iter(&self) -> impl Iterator<Item = (&String, &Value)> {
464 self.columns.iter()
465 }
466}
467
468#[derive(Debug, Clone, PartialEq)]
474pub enum ResultMapError {
475 MapNotFound { id: String },
477 RequiredColumnMissing { column: String },
479 NestedMappingFailed { property: String, reason: String },
481}
482
483impl std::fmt::Display for ResultMapError {
484 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
485 match self {
486 ResultMapError::MapNotFound { id } => {
487 write!(f, "ResultMap '{}' not registered", id)
488 }
489 ResultMapError::RequiredColumnMissing { column } => {
490 write!(f, "Required column '{}' missing in row", column)
491 }
492 ResultMapError::NestedMappingFailed { property, reason } => {
493 write!(f, "Nested mapping failed for '{}': {}", property, reason)
494 }
495 }
496 }
497}
498
499impl std::error::Error for ResultMapError {}
500
501#[tracing::instrument(skip(registry, row), fields(map_id = map_id))]
514pub fn apply_result_map(
515 registry: &ResultMapRegistry,
516 map_id: &str,
517 row: &RowData,
518) -> Result<HashMap<String, Value>, ResultMapError> {
519 let map = registry
520 .get(map_id)
521 .ok_or_else(|| ResultMapError::MapNotFound {
522 id: map_id.to_string(),
523 })?;
524
525 let effective_map = if let Some(disc) = &map.discriminator {
527 if let Some(disc_value) = row.get(&disc.column) {
528 if let Some(case_map_id) = disc.resolve(disc_value) {
529 registry.get(case_map_id).unwrap_or(map)
530 } else {
531 map
532 }
533 } else {
534 map
535 }
536 } else {
537 map
538 };
539
540 let mut attrs: HashMap<String, Value> = HashMap::new();
541
542 for m in &effective_map.id_mappings {
544 if let Some(v) = row.get(&m.column) {
545 attrs.insert(m.property.clone(), v.clone());
546 }
547 }
548 for m in &effective_map.result_mappings {
549 if let Some(v) = row.get(&m.column) {
550 attrs.insert(m.property.clone(), v.clone());
551 }
552 }
553
554 for assoc in &effective_map.associations {
556 if let Some(not_null_col) = &assoc.not_null_column {
558 if !row.is_not_null(not_null_col) {
559 continue; }
561 }
562
563 let nested_value = if let Some(prefix) = &assoc.column_prefix {
565 let mut prefixed_row = RowData::empty();
567 for (col, v) in &row.columns {
568 if let Some(stripped) = col.strip_prefix(prefix) {
569 prefixed_row.set(stripped.to_string(), v.clone());
570 }
571 }
572 apply_result_map(registry, &assoc.result_map, &prefixed_row).map_err(|e| {
573 ResultMapError::NestedMappingFailed {
574 property: assoc.property.clone(),
575 reason: e.to_string(),
576 }
577 })?
578 } else {
579 apply_result_map(registry, &assoc.result_map, row).map_err(|e| {
581 ResultMapError::NestedMappingFailed {
582 property: assoc.property.clone(),
583 reason: e.to_string(),
584 }
585 })?
586 };
587
588 attrs.insert(assoc.property.clone(), Value::Object(nested_value));
590 }
591
592 for coll in &effective_map.collections {
594 if let Some(not_null_col) = &coll.not_null_column {
595 if !row.is_not_null(not_null_col) {
596 continue;
597 }
598 }
599
600 let nested = if let Some(prefix) = &coll.column_prefix {
601 let mut prefixed_row = RowData::empty();
602 for (col, v) in &row.columns {
603 if let Some(stripped) = col.strip_prefix(prefix) {
604 prefixed_row.set(stripped.to_string(), v.clone());
605 }
606 }
607 apply_result_map(registry, &coll.result_map, &prefixed_row).map_err(|e| {
608 ResultMapError::NestedMappingFailed {
609 property: coll.property.clone(),
610 reason: e.to_string(),
611 }
612 })?
613 } else {
614 apply_result_map(registry, &coll.result_map, row).map_err(|e| {
615 ResultMapError::NestedMappingFailed {
616 property: coll.property.clone(),
617 reason: e.to_string(),
618 }
619 })?
620 };
621
622 attrs.insert(
625 coll.property.clone(),
626 Value::Array(vec![Value::Object(nested)]),
627 );
628 }
629
630 Ok(attrs)
631}
632
633#[tracing::instrument(skip(registry, rows), fields(map_id = map_id, row_count = rows.len()))]
641pub fn apply_result_map_many(
642 registry: &ResultMapRegistry,
643 map_id: &str,
644 rows: &[RowData],
645) -> Result<Vec<HashMap<String, Value>>, ResultMapError> {
646 if rows.is_empty() {
647 return Ok(Vec::new());
648 }
649
650 let map = registry
651 .get(map_id)
652 .ok_or_else(|| ResultMapError::MapNotFound {
653 id: map_id.to_string(),
654 })?;
655
656 fn pk_key(attrs: &HashMap<String, Value>, id_mappings: &[Mapping]) -> String {
658 if id_mappings.is_empty() {
659 return String::new();
662 }
663 let mut parts = Vec::new();
664 for m in id_mappings {
665 if let Some(v) = attrs.get(&m.property) {
666 parts.push(format!("{:?}", v));
667 } else {
668 parts.push("null".to_string());
669 }
670 }
671 parts.join("|")
672 }
673
674 let mut ordered_keys: Vec<String> = Vec::new();
676 let mut groups: HashMap<String, HashMap<String, Value>> = HashMap::new();
677 let mut collection_acc: HashMap<String, HashMap<String, Vec<Value>>> = HashMap::new();
678
679 for row in rows {
680 let attrs = apply_result_map(registry, map_id, row)?;
681 let key = pk_key(&attrs, &map.id_mappings);
682
683 if !groups.contains_key(&key) {
684 ordered_keys.push(key.clone());
685 groups.insert(key.clone(), attrs.clone());
686 collection_acc.insert(key.clone(), HashMap::new());
687 }
688
689 for coll in &map.collections {
691 if let Some(Value::Array(items)) = attrs.get(&coll.property) {
692 if !items.is_empty() {
693 let acc = collection_acc.get_mut(&key).ok_or_else(|| {
694 ResultMapError::NestedMappingFailed {
695 property: "collection_acc".to_string(),
696 reason: format!("key '{}' not found in collection_acc", key),
697 }
698 })?;
699 let entry = acc.entry(coll.property.clone()).or_default();
700 for item in items {
701 entry.push(item.clone());
702 }
703 }
704 }
705 }
706 }
707
708 let mut result = Vec::new();
710 for key in ordered_keys {
711 let mut attrs = groups
712 .remove(&key)
713 .ok_or_else(|| ResultMapError::NestedMappingFailed {
714 property: "groups".to_string(),
715 reason: format!("key '{}' not found in groups", key),
716 })?;
717 if let Some(coll_acc) = collection_acc.remove(&key) {
718 for (prop, items) in coll_acc {
719 attrs.insert(prop, Value::Array(items));
720 }
721 }
722 result.push(attrs);
723 }
724
725 Ok(result)
726}
727
728#[derive(Debug, Clone, PartialEq, Eq)]
734pub struct ScalarResult {
735 pub column: String,
737 pub type_name: String,
739}
740
741impl ScalarResult {
742 pub fn new(column: impl Into<String>, type_name: impl Into<String>) -> Self {
743 Self {
744 column: column.into(),
745 type_name: type_name.into(),
746 }
747 }
748}
749
750#[derive(Debug, Clone, PartialEq, Eq)]
752pub struct FieldResult {
753 pub name: String,
754 pub column: String,
755}
756
757impl FieldResult {
758 pub fn new(name: impl Into<String>, column: impl Into<String>) -> Self {
759 Self {
760 name: name.into(),
761 column: column.into(),
762 }
763 }
764}
765
766#[derive(Debug, Clone, PartialEq, Eq)]
768pub struct EntityResult {
769 pub entity_class: String,
770 pub fields: Vec<FieldResult>,
771 pub discriminator_column: Option<String>,
772}
773
774impl EntityResult {
775 pub fn new(entity_class: impl Into<String>) -> Self {
776 Self {
777 entity_class: entity_class.into(),
778 fields: Vec::new(),
779 discriminator_column: None,
780 }
781 }
782
783 pub fn add_field(&mut self, field: FieldResult) -> &mut Self {
784 self.fields.push(field);
785 self
786 }
787
788 pub fn with_discriminator_column(mut self, col: impl Into<String>) -> Self {
789 self.discriminator_column = Some(col.into());
790 self
791 }
792}
793
794#[derive(Debug, Clone, PartialEq)]
796pub struct ResultSetMapping {
797 pub name: String,
798 pub entities: Vec<EntityResult>,
799 pub scalars: Vec<ScalarResult>,
800}
801
802impl ResultSetMapping {
803 pub fn new(name: impl Into<String>) -> Self {
804 Self {
805 name: name.into(),
806 entities: Vec::new(),
807 scalars: Vec::new(),
808 }
809 }
810
811 pub fn add_entity(&mut self, entity: EntityResult) -> &mut Self {
812 self.entities.push(entity);
813 self
814 }
815
816 pub fn add_scalar(&mut self, scalar: ScalarResult) -> &mut Self {
817 self.scalars.push(scalar);
818 self
819 }
820}
821
822#[derive(Debug, Default)]
824pub struct ResultSetMappingRegistry {
825 mappings: RwLock<HashMap<String, ResultSetMapping>>,
826}
827
828impl ResultSetMappingRegistry {
829 pub fn new() -> Self {
830 Self {
831 mappings: RwLock::new(HashMap::new()),
832 }
833 }
834
835 pub fn register(&self, mapping: ResultSetMapping) {
836 let mut m = self.mappings.write();
837 m.insert(mapping.name.clone(), mapping);
838 }
839
840 pub fn get(&self, name: &str) -> Option<ResultSetMapping> {
841 let m = self.mappings.read();
842 m.get(name).cloned()
843 }
844
845 pub fn contains(&self, name: &str) -> bool {
846 let m = self.mappings.read();
847 m.contains_key(name)
848 }
849
850 pub fn len(&self) -> usize {
851 let m = self.mappings.read();
852 m.len()
853 }
854
855 pub fn is_empty(&self) -> bool {
856 self.len() == 0
857 }
858}
859
860#[derive(Debug, Clone)]
862pub struct NativeQuery {
863 pub sql: String,
865 pub result_set_mapping: String,
867 pub parameters: Vec<Value>,
869}
870
871impl NativeQuery {
872 pub fn new(sql: impl Into<String>, mapping_name: impl Into<String>) -> Self {
873 Self {
874 sql: sql.into(),
875 result_set_mapping: mapping_name.into(),
876 parameters: Vec::new(),
877 }
878 }
879
880 pub fn bind(&mut self, value: Value) -> &mut Self {
881 self.parameters.push(value);
882 self
883 }
884
885 pub fn bind_many(&mut self, values: Vec<Value>) -> &mut Self {
886 self.parameters.extend(values);
887 self
888 }
889}
890
891pub fn apply_result_set_mapping(
897 mapping: &ResultSetMapping,
898 row: &RowData,
899) -> ResultSetMappingResult {
900 let mut entities = Vec::new();
901 for ent in &mapping.entities {
902 let mut attrs = HashMap::new();
903 for f in &ent.fields {
904 if let Some(v) = row.get(&f.column) {
905 attrs.insert(f.name.clone(), v.clone());
906 }
907 }
908 entities.push(attrs);
909 }
910
911 let mut scalars = Vec::new();
912 for s in &mapping.scalars {
913 if let Some(v) = row.get(&s.column) {
914 scalars.push(v.clone());
915 } else {
916 scalars.push(Value::Null);
917 }
918 }
919
920 (entities, scalars)
921}
922
923pub type ResultSetMappingResult = (Vec<HashMap<String, Value>>, Vec<Value>);
925
926pub fn apply_result_set_mapping_many(
928 mapping: &ResultSetMapping,
929 rows: &[RowData],
930) -> Vec<ResultSetMappingResult> {
931 rows.iter()
932 .map(|row| apply_result_set_mapping(mapping, row))
933 .collect()
934}
935
936#[cfg(test)]
941mod tests {
942 use super::*;
943
944 #[test]
947 fn test_mapping_new() {
948 let m = Mapping::new("id", "user_id");
949 assert_eq!(m.property, "id");
950 assert_eq!(m.column, "user_id");
951 assert_eq!(m.type_handler, None);
952 }
953
954 #[test]
955 fn test_mapping_with_handler() {
956 let m = Mapping::with_handler("amount", "amount", "money_handler");
957 assert_eq!(m.property, "amount");
958 assert_eq!(m.column, "amount");
959 assert_eq!(m.type_handler.as_deref(), Some("money_handler"));
960 }
961
962 #[test]
965 fn test_association_new() {
966 let a = NestedAssociation::new("dept", "deptMap");
967 assert_eq!(a.property, "dept");
968 assert_eq!(a.result_map, "deptMap");
969 assert_eq!(a.column_prefix, None);
970 assert_eq!(a.not_null_column, None);
971 }
972
973 #[test]
974 fn test_association_with_prefix() {
975 let a = NestedAssociation::new("dept", "deptMap").with_prefix("d_");
976 assert_eq!(a.column_prefix.as_deref(), Some("d_"));
977 }
978
979 #[test]
980 fn test_association_with_not_null_column() {
981 let a = NestedAssociation::new("dept", "deptMap").with_not_null_column("dept_id");
982 assert_eq!(a.not_null_column.as_deref(), Some("dept_id"));
983 }
984
985 #[test]
988 fn test_collection_new() {
989 let c = NestedCollection::new("roles", "roleMap");
990 assert_eq!(c.property, "roles");
991 assert_eq!(c.result_map, "roleMap");
992 assert_eq!(c.column_prefix, None);
993 }
994
995 #[test]
996 fn test_collection_with_prefix() {
997 let c = NestedCollection::new("roles", "roleMap").with_prefix("r_");
998 assert_eq!(c.column_prefix.as_deref(), Some("r_"));
999 }
1000
1001 #[test]
1004 fn test_discriminator_new() {
1005 let d = Discriminator::new("user_type");
1006 assert_eq!(d.column, "user_type");
1007 assert!(d.cases.is_empty());
1008 }
1009
1010 #[test]
1011 fn test_discriminator_add_case() {
1012 let mut d = Discriminator::new("user_type");
1013 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"))
1014 .add_case(DiscriminatorCase::new(Value::I64(2), "userMap"));
1015 assert_eq!(d.cases.len(), 2);
1016 }
1017
1018 #[test]
1019 fn test_discriminator_resolve_hit() {
1020 let mut d = Discriminator::new("user_type");
1021 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"))
1022 .add_case(DiscriminatorCase::new(Value::I64(2), "userMap"));
1023
1024 assert_eq!(d.resolve(&Value::I64(1)), Some("adminMap"));
1025 assert_eq!(d.resolve(&Value::I64(2)), Some("userMap"));
1026 }
1027
1028 #[test]
1029 fn test_discriminator_resolve_miss() {
1030 let mut d = Discriminator::new("user_type");
1031 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1032
1033 assert_eq!(d.resolve(&Value::I64(99)), None);
1034 }
1035
1036 #[test]
1039 fn test_result_map_new() {
1040 let rm = ResultMap::new("userMap", "User");
1041 assert_eq!(rm.id, "userMap");
1042 assert_eq!(rm.type_name, "User");
1043 assert!(rm.id_mappings.is_empty());
1044 assert!(rm.result_mappings.is_empty());
1045 assert!(rm.associations.is_empty());
1046 assert!(rm.collections.is_empty());
1047 assert!(rm.discriminator.is_none());
1048 }
1049
1050 #[test]
1051 fn test_result_map_add_mappings() {
1052 let mut rm = ResultMap::new("userMap", "User");
1053 rm.add_id_mapping(Mapping::new("id", "user_id"))
1054 .add_result_mapping(Mapping::new("name", "user_name"))
1055 .add_association(NestedAssociation::new("dept", "deptMap"))
1056 .add_collection(NestedCollection::new("roles", "roleMap"));
1057
1058 assert_eq!(rm.id_mappings.len(), 1);
1059 assert_eq!(rm.result_mappings.len(), 1);
1060 assert_eq!(rm.associations.len(), 1);
1061 assert_eq!(rm.collections.len(), 1);
1062 }
1063
1064 #[test]
1065 fn test_result_map_set_discriminator() {
1066 let mut rm = ResultMap::new("userMap", "User");
1067 rm.set_discriminator(Discriminator::new("user_type"));
1068 assert!(rm.discriminator.is_some());
1069 assert_eq!(rm.discriminator.as_ref().unwrap().column, "user_type");
1070 }
1071
1072 #[test]
1073 fn test_sub_map_ids() {
1074 let mut rm = ResultMap::new("userMap", "User");
1075 rm.add_association(NestedAssociation::new("dept", "deptMap"))
1076 .add_collection(NestedCollection::new("roles", "roleMap"))
1077 .set_discriminator({
1078 let mut d = Discriminator::new("type");
1079 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1080 d
1081 });
1082
1083 let ids = rm.sub_map_ids();
1084 assert!(ids.contains(&"deptMap".to_string()));
1085 assert!(ids.contains(&"roleMap".to_string()));
1086 assert!(ids.contains(&"adminMap".to_string()));
1087 }
1088
1089 #[test]
1092 fn test_registry_register_and_get() {
1093 let registry = ResultMapRegistry::new();
1094 let rm = ResultMap::new("userMap", "User");
1095 registry.register(rm);
1096
1097 assert!(registry.contains("userMap"));
1098 assert!(!registry.contains("missing"));
1099 assert_eq!(registry.len(), 1);
1100 assert!(registry.get("userMap").is_some());
1101 assert!(registry.get("missing").is_none());
1102 }
1103
1104 #[test]
1105 fn test_registry_list_ids() {
1106 let registry = ResultMapRegistry::new();
1107 registry.register(ResultMap::new("userMap", "User"));
1108 registry.register(ResultMap::new("deptMap", "Dept"));
1109
1110 let ids = registry.list_ids();
1111 assert_eq!(ids.len(), 2);
1112 assert!(ids.contains(&"userMap".to_string()));
1113 assert!(ids.contains(&"deptMap".to_string()));
1114 }
1115
1116 #[test]
1117 fn test_registry_clear() {
1118 let registry = ResultMapRegistry::new();
1119 registry.register(ResultMap::new("userMap", "User"));
1120 assert_eq!(registry.len(), 1);
1121 registry.clear();
1122 assert_eq!(registry.len(), 0);
1123 }
1124
1125 #[test]
1126 fn test_registry_overwrite() {
1127 let registry = ResultMapRegistry::new();
1128 registry.register(ResultMap::new("userMap", "User"));
1129 registry.register(ResultMap::new("userMap", "AdminUser"));
1130
1131 let rm = registry.get("userMap").unwrap();
1132 assert_eq!(rm.type_name, "AdminUser");
1133 }
1134
1135 #[test]
1138 fn test_row_data_new() {
1139 let mut cols = HashMap::new();
1140 cols.insert("id".to_string(), Value::I64(1));
1141 let row = RowData::new(cols);
1142
1143 assert_eq!(row.get("id"), Some(&Value::I64(1)));
1144 assert_eq!(row.get("missing"), None);
1145 assert_eq!(row.len(), 1);
1146 }
1147
1148 #[test]
1149 fn test_row_data_set_and_get() {
1150 let mut row = RowData::empty();
1151 row.set("name", Value::String("Alice".to_string()));
1152
1153 assert_eq!(row.get("name"), Some(&Value::String("Alice".to_string())));
1154 }
1155
1156 #[test]
1157 fn test_row_data_get_with_prefix() {
1158 let mut row = RowData::empty();
1159 row.set("dept_id", Value::I64(10));
1160 row.set("dept_name", Value::String("Engineering".to_string()));
1161
1162 assert_eq!(row.get_with_prefix("dept_", "id"), Some(&Value::I64(10)));
1163 assert_eq!(
1164 row.get_with_prefix("dept_", "name"),
1165 Some(&Value::String("Engineering".to_string()))
1166 );
1167 assert_eq!(row.get_with_prefix("dept_", "missing"), None);
1168 }
1169
1170 #[test]
1171 fn test_row_data_is_not_null() {
1172 let mut row = RowData::empty();
1173 row.set("a", Value::I64(1));
1174 row.set("b", Value::Null);
1175
1176 assert!(row.is_not_null("a"));
1177 assert!(!row.is_not_null("b"));
1178 assert!(!row.is_not_null("missing"));
1179 }
1180
1181 #[test]
1182 fn test_row_data_column_names() {
1183 let mut row = RowData::empty();
1184 row.set("id", Value::I64(1));
1185 row.set("name", Value::String("Alice".to_string()));
1186
1187 let names = row.column_names();
1188 assert_eq!(names.len(), 2);
1189 assert!(names.contains(&"id".to_string()));
1190 assert!(names.contains(&"name".to_string()));
1191 }
1192
1193 #[test]
1196 fn test_apply_result_map_basic() {
1197 let registry = ResultMapRegistry::new();
1198 let mut rm = ResultMap::new("userMap", "User");
1199 rm.add_id_mapping(Mapping::new("id", "user_id"))
1200 .add_result_mapping(Mapping::new("name", "user_name"));
1201 registry.register(rm);
1202
1203 let mut row = RowData::empty();
1204 row.set("user_id", Value::I64(1));
1205 row.set("user_name", Value::String("Alice".to_string()));
1206
1207 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1208 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1209 assert_eq!(attrs.get("name"), Some(&Value::String("Alice".to_string())));
1210 }
1211
1212 #[test]
1213 fn test_apply_result_map_missing_column() {
1214 let registry = ResultMapRegistry::new();
1215 let mut rm = ResultMap::new("userMap", "User");
1216 rm.add_id_mapping(Mapping::new("id", "user_id"))
1217 .add_result_mapping(Mapping::new("name", "user_name"));
1218 registry.register(rm);
1219
1220 let row = RowData::empty();
1221 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1222 assert!(!attrs.contains_key("id"));
1224 assert!(!attrs.contains_key("name"));
1225 }
1226
1227 #[test]
1228 fn test_apply_result_map_not_found() {
1229 let registry = ResultMapRegistry::new();
1230 let row = RowData::empty();
1231 let err = apply_result_map(®istry, "missingMap", &row).unwrap_err();
1232 match err {
1233 ResultMapError::MapNotFound { id } => assert_eq!(id, "missingMap"),
1234 _ => panic!("expected MapNotFound"),
1235 }
1236 }
1237
1238 #[test]
1241 fn test_apply_result_map_with_association() {
1242 let registry = ResultMapRegistry::new();
1243
1244 let mut dept_map = ResultMap::new("deptMap", "Dept");
1245 dept_map
1246 .add_id_mapping(Mapping::new("id", "dept_id"))
1247 .add_result_mapping(Mapping::new("name", "dept_name"));
1248 registry.register(dept_map);
1249
1250 let mut user_map = ResultMap::new("userMap", "User");
1251 user_map
1252 .add_id_mapping(Mapping::new("id", "user_id"))
1253 .add_result_mapping(Mapping::new("name", "user_name"))
1254 .add_association(NestedAssociation::new("dept", "deptMap"));
1255 registry.register(user_map);
1256
1257 let mut row = RowData::empty();
1258 row.set("user_id", Value::I64(1));
1259 row.set("user_name", Value::String("Alice".to_string()));
1260 row.set("dept_id", Value::I64(10));
1261 row.set("dept_name", Value::String("Engineering".to_string()));
1262
1263 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1264 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1265 let dept = attrs.get("dept");
1266 assert!(dept.is_some());
1267 if let Some(Value::Object(dept_attrs)) = dept {
1268 assert_eq!(dept_attrs.get("id"), Some(&Value::I64(10)));
1269 assert_eq!(
1270 dept_attrs.get("name"),
1271 Some(&Value::String("Engineering".to_string()))
1272 );
1273 }
1274 }
1275
1276 #[test]
1277 fn test_apply_result_map_association_not_null_column_skip() {
1278 let registry = ResultMapRegistry::new();
1279
1280 let mut dept_map = ResultMap::new("deptMap", "Dept");
1281 dept_map
1282 .add_id_mapping(Mapping::new("id", "dept_id"))
1283 .add_result_mapping(Mapping::new("name", "dept_name"));
1284 registry.register(dept_map);
1285
1286 let mut user_map = ResultMap::new("userMap", "User");
1287 user_map
1288 .add_id_mapping(Mapping::new("id", "user_id"))
1289 .add_result_mapping(Mapping::new("name", "user_name"))
1290 .add_association(
1291 NestedAssociation::new("dept", "deptMap").with_not_null_column("dept_id"),
1292 );
1293 registry.register(user_map);
1294
1295 let mut row = RowData::empty();
1297 row.set("user_id", Value::I64(1));
1298 row.set("user_name", Value::String("Alice".to_string()));
1299 row.set("dept_id", Value::Null);
1300
1301 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1302 assert!(!attrs.contains_key("dept"));
1304 }
1305
1306 #[test]
1307 fn test_apply_result_map_association_with_prefix() {
1308 let registry = ResultMapRegistry::new();
1309
1310 let mut dept_map = ResultMap::new("deptMap", "Dept");
1311 dept_map
1312 .add_id_mapping(Mapping::new("id", "id"))
1313 .add_result_mapping(Mapping::new("name", "name"));
1314 registry.register(dept_map);
1315
1316 let mut user_map = ResultMap::new("userMap", "User");
1317 user_map
1318 .add_id_mapping(Mapping::new("id", "id"))
1319 .add_result_mapping(Mapping::new("name", "name"))
1320 .add_association(NestedAssociation::new("dept", "deptMap").with_prefix("d_"));
1321 registry.register(user_map);
1322
1323 let mut row = RowData::empty();
1325 row.set("id", Value::I64(1));
1326 row.set("name", Value::String("Alice".to_string()));
1327 row.set("d_id", Value::I64(10));
1328 row.set("d_name", Value::String("Engineering".to_string()));
1329
1330 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1331 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1332 assert_eq!(attrs.get("name"), Some(&Value::String("Alice".to_string())));
1333
1334 if let Some(Value::Object(dept_attrs)) = attrs.get("dept") {
1335 assert_eq!(dept_attrs.get("id"), Some(&Value::I64(10)));
1336 assert_eq!(
1337 dept_attrs.get("name"),
1338 Some(&Value::String("Engineering".to_string()))
1339 );
1340 } else {
1341 panic!("dept should be an Object");
1342 }
1343 }
1344
1345 #[test]
1348 fn test_apply_result_map_discriminator() {
1349 let registry = ResultMapRegistry::new();
1350
1351 let mut admin_map = ResultMap::new("adminMap", "AdminUser");
1353 admin_map
1354 .add_id_mapping(Mapping::new("id", "user_id"))
1355 .add_result_mapping(Mapping::new("name", "user_name"))
1356 .add_result_mapping(Mapping::new("admin_level", "extra_level"));
1357 registry.register(admin_map);
1358
1359 let mut normal_map = ResultMap::new("normalMap", "NormalUser");
1361 normal_map
1362 .add_id_mapping(Mapping::new("id", "user_id"))
1363 .add_result_mapping(Mapping::new("name", "user_name"));
1364 registry.register(normal_map);
1365
1366 let mut base_map = ResultMap::new("baseMap", "User");
1368 base_map
1369 .add_id_mapping(Mapping::new("id", "user_id"))
1370 .add_result_mapping(Mapping::new("name", "user_name"))
1371 .set_discriminator({
1372 let mut d = Discriminator::new("user_type");
1373 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1374 d.add_case(DiscriminatorCase::new(Value::I64(2), "normalMap"));
1375 d
1376 });
1377 registry.register(base_map);
1378
1379 let mut row = RowData::empty();
1381 row.set("user_id", Value::I64(1));
1382 row.set("user_name", Value::String("Alice".to_string()));
1383 row.set("user_type", Value::I64(1));
1384 row.set("extra_level", Value::I64(5));
1385
1386 let attrs = apply_result_map(®istry, "baseMap", &row).unwrap();
1387 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1388 assert_eq!(attrs.get("admin_level"), Some(&Value::I64(5)));
1389
1390 let mut row2 = RowData::empty();
1392 row2.set("user_id", Value::I64(2));
1393 row2.set("user_name", Value::String("Bob".to_string()));
1394 row2.set("user_type", Value::I64(2));
1395
1396 let attrs2 = apply_result_map(®istry, "baseMap", &row2).unwrap();
1397 assert_eq!(attrs2.get("id"), Some(&Value::I64(2)));
1398 assert!(!attrs2.contains_key("admin_level")); }
1400
1401 #[test]
1402 fn test_apply_result_map_discriminator_no_match_falls_back_to_base() {
1403 let registry = ResultMapRegistry::new();
1404
1405 let mut base_map = ResultMap::new("baseMap", "User");
1406 base_map
1407 .add_id_mapping(Mapping::new("id", "user_id"))
1408 .set_discriminator({
1409 let mut d = Discriminator::new("user_type");
1410 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1411 d
1412 });
1413 registry.register(base_map);
1414
1415 let mut row = RowData::empty();
1417 row.set("user_id", Value::I64(1));
1418 row.set("user_type", Value::I64(99));
1419
1420 let attrs = apply_result_map(®istry, "baseMap", &row).unwrap();
1421 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1422 }
1423
1424 #[test]
1427 fn test_apply_result_map_many_collection_aggregation() {
1428 let registry = ResultMapRegistry::new();
1429
1430 let mut role_map = ResultMap::new("roleMap", "Role");
1431 role_map
1432 .add_id_mapping(Mapping::new("id", "role_id"))
1433 .add_result_mapping(Mapping::new("name", "role_name"));
1434 registry.register(role_map);
1435
1436 let mut user_map = ResultMap::new("userMap", "User");
1437 user_map
1438 .add_id_mapping(Mapping::new("id", "user_id"))
1439 .add_result_mapping(Mapping::new("name", "user_name"))
1440 .add_collection(NestedCollection::new("roles", "roleMap"));
1441 registry.register(user_map);
1442
1443 let rows = vec![
1445 {
1446 let mut r = RowData::empty();
1447 r.set("user_id", Value::I64(1));
1448 r.set("user_name", Value::String("Alice".to_string()));
1449 r.set("role_id", Value::I64(100));
1450 r.set("role_name", Value::String("admin".to_string()));
1451 r
1452 },
1453 {
1454 let mut r = RowData::empty();
1455 r.set("user_id", Value::I64(1));
1456 r.set("user_name", Value::String("Alice".to_string()));
1457 r.set("role_id", Value::I64(101));
1458 r.set("role_name", Value::String("editor".to_string()));
1459 r
1460 },
1461 ];
1462
1463 let result = apply_result_map_many(®istry, "userMap", &rows).unwrap();
1464 assert_eq!(result.len(), 1); let user = &result[0];
1466 assert_eq!(user.get("id"), Some(&Value::I64(1)));
1467 let roles = user.get("roles");
1468 assert!(roles.is_some());
1469 if let Some(Value::Array(items)) = roles {
1470 assert_eq!(items.len(), 2);
1471 }
1472 }
1473
1474 #[test]
1475 fn test_apply_result_map_many_multi_users() {
1476 let registry = ResultMapRegistry::new();
1477
1478 let mut role_map = ResultMap::new("roleMap", "Role");
1479 role_map
1480 .add_id_mapping(Mapping::new("id", "role_id"))
1481 .add_result_mapping(Mapping::new("name", "role_name"));
1482 registry.register(role_map);
1483
1484 let mut user_map = ResultMap::new("userMap", "User");
1485 user_map
1486 .add_id_mapping(Mapping::new("id", "user_id"))
1487 .add_result_mapping(Mapping::new("name", "user_name"))
1488 .add_collection(NestedCollection::new("roles", "roleMap"));
1489 registry.register(user_map);
1490
1491 let rows = vec![
1492 {
1493 let mut r = RowData::empty();
1494 r.set("user_id", Value::I64(1));
1495 r.set("user_name", Value::String("Alice".to_string()));
1496 r.set("role_id", Value::I64(100));
1497 r.set("role_name", Value::String("admin".to_string()));
1498 r
1499 },
1500 {
1501 let mut r = RowData::empty();
1502 r.set("user_id", Value::I64(2));
1503 r.set("user_name", Value::String("Bob".to_string()));
1504 r.set("role_id", Value::I64(101));
1505 r.set("role_name", Value::String("editor".to_string()));
1506 r
1507 },
1508 ];
1509
1510 let result = apply_result_map_many(®istry, "userMap", &rows).unwrap();
1511 assert_eq!(result.len(), 2);
1512 assert_eq!(result[0].get("id"), Some(&Value::I64(1)));
1514 assert_eq!(result[1].get("id"), Some(&Value::I64(2)));
1515 }
1516
1517 #[test]
1518 fn test_apply_result_map_many_empty() {
1519 let registry = ResultMapRegistry::new();
1520 registry.register(ResultMap::new("userMap", "User"));
1521
1522 let result = apply_result_map_many(®istry, "userMap", &[]).unwrap();
1523 assert!(result.is_empty());
1524 }
1525
1526 #[test]
1529 fn test_entity_result_new() {
1530 let er = EntityResult::new("User");
1531 assert_eq!(er.entity_class, "User");
1532 assert!(er.fields.is_empty());
1533 assert_eq!(er.discriminator_column, None);
1534 }
1535
1536 #[test]
1537 fn test_entity_result_add_field() {
1538 let mut er = EntityResult::new("User");
1539 er.add_field(FieldResult::new("id", "user_id"))
1540 .add_field(FieldResult::new("name", "user_name"));
1541 assert_eq!(er.fields.len(), 2);
1542 }
1543
1544 #[test]
1545 fn test_entity_result_with_discriminator() {
1546 let er = EntityResult::new("User").with_discriminator_column("user_type");
1547 assert_eq!(er.discriminator_column.as_deref(), Some("user_type"));
1548 }
1549
1550 #[test]
1551 fn test_scalar_result_new() {
1552 let s = ScalarResult::new("count", "i64");
1553 assert_eq!(s.column, "count");
1554 assert_eq!(s.type_name, "i64");
1555 }
1556
1557 #[test]
1558 fn test_result_set_mapping_new() {
1559 let rsm = ResultSetMapping::new("userCount");
1560 assert_eq!(rsm.name, "userCount");
1561 assert!(rsm.entities.is_empty());
1562 assert!(rsm.scalars.is_empty());
1563 }
1564
1565 #[test]
1566 fn test_result_set_mapping_add() {
1567 let mut rsm = ResultSetMapping::new("userWithCount");
1568 rsm.add_entity(EntityResult::new("User"))
1569 .add_scalar(ScalarResult::new("total", "i64"));
1570 assert_eq!(rsm.entities.len(), 1);
1571 assert_eq!(rsm.scalars.len(), 1);
1572 }
1573
1574 #[test]
1577 fn test_rsm_registry() {
1578 let reg = ResultSetMappingRegistry::new();
1579 reg.register(ResultSetMapping::new("mapping1"));
1580 assert!(reg.contains("mapping1"));
1581 assert!(!reg.contains("missing"));
1582 assert_eq!(reg.len(), 1);
1583 assert!(reg.get("mapping1").is_some());
1584 assert!(reg.get("missing").is_none());
1585 }
1586
1587 #[test]
1590 fn test_native_query_new() {
1591 let nq = NativeQuery::new("SELECT * FROM users WHERE id = ?", "userMapping");
1592 assert_eq!(nq.sql, "SELECT * FROM users WHERE id = ?");
1593 assert_eq!(nq.result_set_mapping, "userMapping");
1594 assert!(nq.parameters.is_empty());
1595 }
1596
1597 #[test]
1598 fn test_native_query_bind() {
1599 let mut nq = NativeQuery::new("SELECT * FROM users WHERE id = ?", "userMapping");
1600 nq.bind(Value::I64(1));
1601 assert_eq!(nq.parameters.len(), 1);
1602 assert_eq!(nq.parameters[0], Value::I64(1));
1603 }
1604
1605 #[test]
1606 fn test_native_query_bind_many() {
1607 let mut nq = NativeQuery::new("SELECT * FROM users WHERE id IN (?, ?)", "userMapping");
1608 nq.bind_many(vec![Value::I64(1), Value::I64(2)]);
1609 assert_eq!(nq.parameters.len(), 2);
1610 }
1611
1612 #[test]
1615 fn test_apply_result_set_mapping_entities_only() {
1616 let mut rsm = ResultSetMapping::new("userMapping");
1617 let mut er = EntityResult::new("User");
1618 er.add_field(FieldResult::new("id", "user_id"))
1619 .add_field(FieldResult::new("name", "user_name"));
1620 rsm.add_entity(er);
1621
1622 let mut row = RowData::empty();
1623 row.set("user_id", Value::I64(1));
1624 row.set("user_name", Value::String("Alice".to_string()));
1625
1626 let (entities, scalars) = apply_result_set_mapping(&rsm, &row);
1627 assert_eq!(entities.len(), 1);
1628 assert_eq!(entities[0].get("id"), Some(&Value::I64(1)));
1629 assert_eq!(
1630 entities[0].get("name"),
1631 Some(&Value::String("Alice".to_string()))
1632 );
1633 assert!(scalars.is_empty());
1634 }
1635
1636 #[test]
1637 fn test_apply_result_set_mapping_scalars_only() {
1638 let mut rsm = ResultSetMapping::new("countMapping");
1639 rsm.add_scalar(ScalarResult::new("total", "i64"))
1640 .add_scalar(ScalarResult::new("avg_age", "f64"));
1641
1642 let mut row = RowData::empty();
1643 row.set("total", Value::I64(100));
1644 row.set("avg_age", Value::F64(25.5));
1645
1646 let (entities, scalars) = apply_result_set_mapping(&rsm, &row);
1647 assert!(entities.is_empty());
1648 assert_eq!(scalars.len(), 2);
1649 assert_eq!(scalars[0], Value::I64(100));
1650 assert_eq!(scalars[1], Value::F64(25.5));
1651 }
1652
1653 #[test]
1654 fn test_apply_result_set_mapping_mixed() {
1655 let mut rsm = ResultSetMapping::new("userWithCount");
1656 let mut er = EntityResult::new("User");
1657 er.add_field(FieldResult::new("id", "user_id"))
1658 .add_field(FieldResult::new("name", "user_name"));
1659 rsm.add_entity(er);
1660 rsm.add_scalar(ScalarResult::new("total_orders", "i64"));
1661
1662 let mut row = RowData::empty();
1663 row.set("user_id", Value::I64(1));
1664 row.set("user_name", Value::String("Alice".to_string()));
1665 row.set("total_orders", Value::I64(42));
1666
1667 let (entities, scalars) = apply_result_set_mapping(&rsm, &row);
1668 assert_eq!(entities.len(), 1);
1669 assert_eq!(scalars.len(), 1);
1670 assert_eq!(entities[0].get("id"), Some(&Value::I64(1)));
1671 assert_eq!(scalars[0], Value::I64(42));
1672 }
1673
1674 #[test]
1675 fn test_apply_result_set_mapping_many() {
1676 let mut rsm = ResultSetMapping::new("userMapping");
1677 let mut er = EntityResult::new("User");
1678 er.add_field(FieldResult::new("id", "user_id"));
1679 rsm.add_entity(er);
1680
1681 let rows = vec![
1682 {
1683 let mut r = RowData::empty();
1684 r.set("user_id", Value::I64(1));
1685 r
1686 },
1687 {
1688 let mut r = RowData::empty();
1689 r.set("user_id", Value::I64(2));
1690 r
1691 },
1692 ];
1693
1694 let results = apply_result_set_mapping_many(&rsm, &rows);
1695 assert_eq!(results.len(), 2);
1696 assert_eq!(results[0].0[0].get("id"), Some(&Value::I64(1)));
1697 assert_eq!(results[1].0[0].get("id"), Some(&Value::I64(2)));
1698 }
1699
1700 #[test]
1703 fn test_e2e_user_with_dept_and_roles() {
1704 let registry = ResultMapRegistry::new();
1705
1706 let mut role_map = ResultMap::new("roleMap", "Role");
1708 role_map
1709 .add_id_mapping(Mapping::new("id", "role_id"))
1710 .add_result_mapping(Mapping::new("name", "role_name"));
1711 registry.register(role_map);
1712
1713 let mut dept_map = ResultMap::new("deptMap", "Dept");
1715 dept_map
1716 .add_id_mapping(Mapping::new("id", "dept_id"))
1717 .add_result_mapping(Mapping::new("name", "dept_name"));
1718 registry.register(dept_map);
1719
1720 let mut user_map = ResultMap::new("userMap", "User");
1722 user_map
1723 .add_id_mapping(Mapping::new("id", "user_id"))
1724 .add_result_mapping(Mapping::new("name", "user_name"))
1725 .add_association(NestedAssociation::new("dept", "deptMap"))
1726 .add_collection(NestedCollection::new("roles", "roleMap"));
1727 registry.register(user_map);
1728
1729 let rows = vec![
1731 {
1732 let mut r = RowData::empty();
1733 r.set("user_id", Value::I64(1));
1734 r.set("user_name", Value::String("Alice".to_string()));
1735 r.set("dept_id", Value::I64(10));
1736 r.set("dept_name", Value::String("Engineering".to_string()));
1737 r.set("role_id", Value::I64(100));
1738 r.set("role_name", Value::String("admin".to_string()));
1739 r
1740 },
1741 {
1742 let mut r = RowData::empty();
1743 r.set("user_id", Value::I64(1));
1744 r.set("user_name", Value::String("Alice".to_string()));
1745 r.set("dept_id", Value::I64(10));
1746 r.set("dept_name", Value::String("Engineering".to_string()));
1747 r.set("role_id", Value::I64(101));
1748 r.set("role_name", Value::String("editor".to_string()));
1749 r
1750 },
1751 ];
1752
1753 let result = apply_result_map_many(®istry, "userMap", &rows).unwrap();
1754 assert_eq!(result.len(), 1);
1755 let user = &result[0];
1756 assert_eq!(user.get("id"), Some(&Value::I64(1)));
1757 assert_eq!(user.get("name"), Some(&Value::String("Alice".to_string())));
1758
1759 if let Some(Value::Object(dept_attrs)) = user.get("dept") {
1761 assert_eq!(dept_attrs.get("id"), Some(&Value::I64(10)));
1762 assert_eq!(
1763 dept_attrs.get("name"),
1764 Some(&Value::String("Engineering".to_string()))
1765 );
1766 } else {
1767 panic!("dept should be an Object");
1768 }
1769
1770 if let Some(Value::Array(roles)) = user.get("roles") {
1772 assert_eq!(roles.len(), 2);
1773 } else {
1774 panic!("roles should be an Array");
1775 }
1776 }
1777
1778 #[test]
1779 fn test_e2e_native_query_with_rsm() {
1780 let mut rsm = ResultSetMapping::new("userOrderCount");
1784 let mut er = EntityResult::new("User");
1785 er.add_field(FieldResult::new("id", "user_id"))
1786 .add_field(FieldResult::new("name", "user_name"));
1787 rsm.add_entity(er);
1788 rsm.add_scalar(ScalarResult::new("order_count", "i64"));
1789
1790 let mut nq = NativeQuery::new(
1791 "SELECT u.id AS user_id, u.name AS user_name, COUNT(o.id) AS order_count FROM users u LEFT JOIN orders o ON o.user_id = u.id GROUP BY u.id",
1792 "userOrderCount",
1793 );
1794 nq.bind(Value::Null); let rows = vec![
1798 {
1799 let mut r = RowData::empty();
1800 r.set("user_id", Value::I64(1));
1801 r.set("user_name", Value::String("Alice".to_string()));
1802 r.set("order_count", Value::I64(5));
1803 r
1804 },
1805 {
1806 let mut r = RowData::empty();
1807 r.set("user_id", Value::I64(2));
1808 r.set("user_name", Value::String("Bob".to_string()));
1809 r.set("order_count", Value::I64(3));
1810 r
1811 },
1812 ];
1813
1814 let reg = ResultSetMappingRegistry::new();
1815 reg.register(rsm.clone());
1816 assert!(reg.contains("userOrderCount"));
1817
1818 let results = apply_result_set_mapping_many(&rsm, &rows);
1819 assert_eq!(results.len(), 2);
1820 assert_eq!(results[0].0[0].get("id"), Some(&Value::I64(1)));
1821 assert_eq!(results[0].1[0], Value::I64(5));
1822 assert_eq!(results[1].0[0].get("id"), Some(&Value::I64(2)));
1823 assert_eq!(results[1].1[0], Value::I64(3));
1824
1825 assert_eq!(nq.result_set_mapping, "userOrderCount");
1827 assert_eq!(nq.parameters.len(), 1);
1828 }
1829}