1use crate::value::Value;
64use std::collections::HashMap;
65use std::sync::RwLock;
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().unwrap();
352 maps.insert(map.id.clone(), map);
353 }
354
355 pub fn get(&self, id: &str) -> Option<ResultMap> {
357 let maps = self.maps.read().unwrap();
358 maps.get(id).cloned()
359 }
360
361 pub fn contains(&self, id: &str) -> bool {
363 let maps = self.maps.read().unwrap();
364 maps.contains_key(id)
365 }
366
367 pub fn len(&self) -> usize {
369 let maps = self.maps.read().unwrap();
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().unwrap();
381 maps.keys().cloned().collect()
382 }
383
384 pub fn clear(&self) {
386 let mut maps = self.maps.write().unwrap();
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).unwrap();
694 let entry = acc.entry(coll.property.clone()).or_default();
695 for item in items {
696 entry.push(item.clone());
697 }
698 }
699 }
700 }
701 }
702
703 let mut result = Vec::new();
705 for key in ordered_keys {
706 let mut attrs = groups.remove(&key).unwrap();
707 if let Some(coll_acc) = collection_acc.remove(&key) {
708 for (prop, items) in coll_acc {
709 attrs.insert(prop, Value::Array(items));
710 }
711 }
712 result.push(attrs);
713 }
714
715 Ok(result)
716}
717
718#[derive(Debug, Clone, PartialEq, Eq)]
724pub struct ScalarResult {
725 pub column: String,
727 pub type_name: String,
729}
730
731impl ScalarResult {
732 pub fn new(column: impl Into<String>, type_name: impl Into<String>) -> Self {
733 Self {
734 column: column.into(),
735 type_name: type_name.into(),
736 }
737 }
738}
739
740#[derive(Debug, Clone, PartialEq, Eq)]
742pub struct FieldResult {
743 pub name: String,
744 pub column: String,
745}
746
747impl FieldResult {
748 pub fn new(name: impl Into<String>, column: impl Into<String>) -> Self {
749 Self {
750 name: name.into(),
751 column: column.into(),
752 }
753 }
754}
755
756#[derive(Debug, Clone, PartialEq, Eq)]
758pub struct EntityResult {
759 pub entity_class: String,
760 pub fields: Vec<FieldResult>,
761 pub discriminator_column: Option<String>,
762}
763
764impl EntityResult {
765 pub fn new(entity_class: impl Into<String>) -> Self {
766 Self {
767 entity_class: entity_class.into(),
768 fields: Vec::new(),
769 discriminator_column: None,
770 }
771 }
772
773 pub fn add_field(&mut self, field: FieldResult) -> &mut Self {
774 self.fields.push(field);
775 self
776 }
777
778 pub fn with_discriminator_column(mut self, col: impl Into<String>) -> Self {
779 self.discriminator_column = Some(col.into());
780 self
781 }
782}
783
784#[derive(Debug, Clone, PartialEq)]
786pub struct ResultSetMapping {
787 pub name: String,
788 pub entities: Vec<EntityResult>,
789 pub scalars: Vec<ScalarResult>,
790}
791
792impl ResultSetMapping {
793 pub fn new(name: impl Into<String>) -> Self {
794 Self {
795 name: name.into(),
796 entities: Vec::new(),
797 scalars: Vec::new(),
798 }
799 }
800
801 pub fn add_entity(&mut self, entity: EntityResult) -> &mut Self {
802 self.entities.push(entity);
803 self
804 }
805
806 pub fn add_scalar(&mut self, scalar: ScalarResult) -> &mut Self {
807 self.scalars.push(scalar);
808 self
809 }
810}
811
812#[derive(Debug, Default)]
814pub struct ResultSetMappingRegistry {
815 mappings: RwLock<HashMap<String, ResultSetMapping>>,
816}
817
818impl ResultSetMappingRegistry {
819 pub fn new() -> Self {
820 Self {
821 mappings: RwLock::new(HashMap::new()),
822 }
823 }
824
825 pub fn register(&self, mapping: ResultSetMapping) {
826 let mut m = self.mappings.write().unwrap();
827 m.insert(mapping.name.clone(), mapping);
828 }
829
830 pub fn get(&self, name: &str) -> Option<ResultSetMapping> {
831 let m = self.mappings.read().unwrap();
832 m.get(name).cloned()
833 }
834
835 pub fn contains(&self, name: &str) -> bool {
836 let m = self.mappings.read().unwrap();
837 m.contains_key(name)
838 }
839
840 pub fn len(&self) -> usize {
841 let m = self.mappings.read().unwrap();
842 m.len()
843 }
844
845 pub fn is_empty(&self) -> bool {
846 self.len() == 0
847 }
848}
849
850#[derive(Debug, Clone)]
852pub struct NativeQuery {
853 pub sql: String,
855 pub result_set_mapping: String,
857 pub parameters: Vec<Value>,
859}
860
861impl NativeQuery {
862 pub fn new(sql: impl Into<String>, mapping_name: impl Into<String>) -> Self {
863 Self {
864 sql: sql.into(),
865 result_set_mapping: mapping_name.into(),
866 parameters: Vec::new(),
867 }
868 }
869
870 pub fn bind(&mut self, value: Value) -> &mut Self {
871 self.parameters.push(value);
872 self
873 }
874
875 pub fn bind_many(&mut self, values: Vec<Value>) -> &mut Self {
876 self.parameters.extend(values);
877 self
878 }
879}
880
881pub fn apply_result_set_mapping(
887 mapping: &ResultSetMapping,
888 row: &RowData,
889) -> ResultSetMappingResult {
890 let mut entities = Vec::new();
891 for ent in &mapping.entities {
892 let mut attrs = HashMap::new();
893 for f in &ent.fields {
894 if let Some(v) = row.get(&f.column) {
895 attrs.insert(f.name.clone(), v.clone());
896 }
897 }
898 entities.push(attrs);
899 }
900
901 let mut scalars = Vec::new();
902 for s in &mapping.scalars {
903 if let Some(v) = row.get(&s.column) {
904 scalars.push(v.clone());
905 } else {
906 scalars.push(Value::Null);
907 }
908 }
909
910 (entities, scalars)
911}
912
913pub type ResultSetMappingResult = (Vec<HashMap<String, Value>>, Vec<Value>);
915
916pub fn apply_result_set_mapping_many(
918 mapping: &ResultSetMapping,
919 rows: &[RowData],
920) -> Vec<ResultSetMappingResult> {
921 rows.iter()
922 .map(|row| apply_result_set_mapping(mapping, row))
923 .collect()
924}
925
926#[cfg(test)]
931mod tests {
932 use super::*;
933
934 #[test]
937 fn test_mapping_new() {
938 let m = Mapping::new("id", "user_id");
939 assert_eq!(m.property, "id");
940 assert_eq!(m.column, "user_id");
941 assert_eq!(m.type_handler, None);
942 }
943
944 #[test]
945 fn test_mapping_with_handler() {
946 let m = Mapping::with_handler("amount", "amount", "money_handler");
947 assert_eq!(m.property, "amount");
948 assert_eq!(m.column, "amount");
949 assert_eq!(m.type_handler.as_deref(), Some("money_handler"));
950 }
951
952 #[test]
955 fn test_association_new() {
956 let a = NestedAssociation::new("dept", "deptMap");
957 assert_eq!(a.property, "dept");
958 assert_eq!(a.result_map, "deptMap");
959 assert_eq!(a.column_prefix, None);
960 assert_eq!(a.not_null_column, None);
961 }
962
963 #[test]
964 fn test_association_with_prefix() {
965 let a = NestedAssociation::new("dept", "deptMap").with_prefix("d_");
966 assert_eq!(a.column_prefix.as_deref(), Some("d_"));
967 }
968
969 #[test]
970 fn test_association_with_not_null_column() {
971 let a = NestedAssociation::new("dept", "deptMap").with_not_null_column("dept_id");
972 assert_eq!(a.not_null_column.as_deref(), Some("dept_id"));
973 }
974
975 #[test]
978 fn test_collection_new() {
979 let c = NestedCollection::new("roles", "roleMap");
980 assert_eq!(c.property, "roles");
981 assert_eq!(c.result_map, "roleMap");
982 assert_eq!(c.column_prefix, None);
983 }
984
985 #[test]
986 fn test_collection_with_prefix() {
987 let c = NestedCollection::new("roles", "roleMap").with_prefix("r_");
988 assert_eq!(c.column_prefix.as_deref(), Some("r_"));
989 }
990
991 #[test]
994 fn test_discriminator_new() {
995 let d = Discriminator::new("user_type");
996 assert_eq!(d.column, "user_type");
997 assert!(d.cases.is_empty());
998 }
999
1000 #[test]
1001 fn test_discriminator_add_case() {
1002 let mut d = Discriminator::new("user_type");
1003 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"))
1004 .add_case(DiscriminatorCase::new(Value::I64(2), "userMap"));
1005 assert_eq!(d.cases.len(), 2);
1006 }
1007
1008 #[test]
1009 fn test_discriminator_resolve_hit() {
1010 let mut d = Discriminator::new("user_type");
1011 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"))
1012 .add_case(DiscriminatorCase::new(Value::I64(2), "userMap"));
1013
1014 assert_eq!(d.resolve(&Value::I64(1)), Some("adminMap"));
1015 assert_eq!(d.resolve(&Value::I64(2)), Some("userMap"));
1016 }
1017
1018 #[test]
1019 fn test_discriminator_resolve_miss() {
1020 let mut d = Discriminator::new("user_type");
1021 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1022
1023 assert_eq!(d.resolve(&Value::I64(99)), None);
1024 }
1025
1026 #[test]
1029 fn test_result_map_new() {
1030 let rm = ResultMap::new("userMap", "User");
1031 assert_eq!(rm.id, "userMap");
1032 assert_eq!(rm.type_name, "User");
1033 assert!(rm.id_mappings.is_empty());
1034 assert!(rm.result_mappings.is_empty());
1035 assert!(rm.associations.is_empty());
1036 assert!(rm.collections.is_empty());
1037 assert!(rm.discriminator.is_none());
1038 }
1039
1040 #[test]
1041 fn test_result_map_add_mappings() {
1042 let mut rm = ResultMap::new("userMap", "User");
1043 rm.add_id_mapping(Mapping::new("id", "user_id"))
1044 .add_result_mapping(Mapping::new("name", "user_name"))
1045 .add_association(NestedAssociation::new("dept", "deptMap"))
1046 .add_collection(NestedCollection::new("roles", "roleMap"));
1047
1048 assert_eq!(rm.id_mappings.len(), 1);
1049 assert_eq!(rm.result_mappings.len(), 1);
1050 assert_eq!(rm.associations.len(), 1);
1051 assert_eq!(rm.collections.len(), 1);
1052 }
1053
1054 #[test]
1055 fn test_result_map_set_discriminator() {
1056 let mut rm = ResultMap::new("userMap", "User");
1057 rm.set_discriminator(Discriminator::new("user_type"));
1058 assert!(rm.discriminator.is_some());
1059 assert_eq!(rm.discriminator.as_ref().unwrap().column, "user_type");
1060 }
1061
1062 #[test]
1063 fn test_sub_map_ids() {
1064 let mut rm = ResultMap::new("userMap", "User");
1065 rm.add_association(NestedAssociation::new("dept", "deptMap"))
1066 .add_collection(NestedCollection::new("roles", "roleMap"))
1067 .set_discriminator({
1068 let mut d = Discriminator::new("type");
1069 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1070 d
1071 });
1072
1073 let ids = rm.sub_map_ids();
1074 assert!(ids.contains(&"deptMap".to_string()));
1075 assert!(ids.contains(&"roleMap".to_string()));
1076 assert!(ids.contains(&"adminMap".to_string()));
1077 }
1078
1079 #[test]
1082 fn test_registry_register_and_get() {
1083 let registry = ResultMapRegistry::new();
1084 let rm = ResultMap::new("userMap", "User");
1085 registry.register(rm);
1086
1087 assert!(registry.contains("userMap"));
1088 assert!(!registry.contains("missing"));
1089 assert_eq!(registry.len(), 1);
1090 assert!(registry.get("userMap").is_some());
1091 assert!(registry.get("missing").is_none());
1092 }
1093
1094 #[test]
1095 fn test_registry_list_ids() {
1096 let registry = ResultMapRegistry::new();
1097 registry.register(ResultMap::new("userMap", "User"));
1098 registry.register(ResultMap::new("deptMap", "Dept"));
1099
1100 let ids = registry.list_ids();
1101 assert_eq!(ids.len(), 2);
1102 assert!(ids.contains(&"userMap".to_string()));
1103 assert!(ids.contains(&"deptMap".to_string()));
1104 }
1105
1106 #[test]
1107 fn test_registry_clear() {
1108 let registry = ResultMapRegistry::new();
1109 registry.register(ResultMap::new("userMap", "User"));
1110 assert_eq!(registry.len(), 1);
1111 registry.clear();
1112 assert_eq!(registry.len(), 0);
1113 }
1114
1115 #[test]
1116 fn test_registry_overwrite() {
1117 let registry = ResultMapRegistry::new();
1118 registry.register(ResultMap::new("userMap", "User"));
1119 registry.register(ResultMap::new("userMap", "AdminUser"));
1120
1121 let rm = registry.get("userMap").unwrap();
1122 assert_eq!(rm.type_name, "AdminUser");
1123 }
1124
1125 #[test]
1128 fn test_row_data_new() {
1129 let mut cols = HashMap::new();
1130 cols.insert("id".to_string(), Value::I64(1));
1131 let row = RowData::new(cols);
1132
1133 assert_eq!(row.get("id"), Some(&Value::I64(1)));
1134 assert_eq!(row.get("missing"), None);
1135 assert_eq!(row.len(), 1);
1136 }
1137
1138 #[test]
1139 fn test_row_data_set_and_get() {
1140 let mut row = RowData::empty();
1141 row.set("name", Value::String("Alice".to_string()));
1142
1143 assert_eq!(row.get("name"), Some(&Value::String("Alice".to_string())));
1144 }
1145
1146 #[test]
1147 fn test_row_data_get_with_prefix() {
1148 let mut row = RowData::empty();
1149 row.set("dept_id", Value::I64(10));
1150 row.set("dept_name", Value::String("Engineering".to_string()));
1151
1152 assert_eq!(row.get_with_prefix("dept_", "id"), Some(&Value::I64(10)));
1153 assert_eq!(
1154 row.get_with_prefix("dept_", "name"),
1155 Some(&Value::String("Engineering".to_string()))
1156 );
1157 assert_eq!(row.get_with_prefix("dept_", "missing"), None);
1158 }
1159
1160 #[test]
1161 fn test_row_data_is_not_null() {
1162 let mut row = RowData::empty();
1163 row.set("a", Value::I64(1));
1164 row.set("b", Value::Null);
1165
1166 assert!(row.is_not_null("a"));
1167 assert!(!row.is_not_null("b"));
1168 assert!(!row.is_not_null("missing"));
1169 }
1170
1171 #[test]
1172 fn test_row_data_column_names() {
1173 let mut row = RowData::empty();
1174 row.set("id", Value::I64(1));
1175 row.set("name", Value::String("Alice".to_string()));
1176
1177 let names = row.column_names();
1178 assert_eq!(names.len(), 2);
1179 assert!(names.contains(&"id".to_string()));
1180 assert!(names.contains(&"name".to_string()));
1181 }
1182
1183 #[test]
1186 fn test_apply_result_map_basic() {
1187 let registry = ResultMapRegistry::new();
1188 let mut rm = ResultMap::new("userMap", "User");
1189 rm.add_id_mapping(Mapping::new("id", "user_id"))
1190 .add_result_mapping(Mapping::new("name", "user_name"));
1191 registry.register(rm);
1192
1193 let mut row = RowData::empty();
1194 row.set("user_id", Value::I64(1));
1195 row.set("user_name", Value::String("Alice".to_string()));
1196
1197 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1198 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1199 assert_eq!(attrs.get("name"), Some(&Value::String("Alice".to_string())));
1200 }
1201
1202 #[test]
1203 fn test_apply_result_map_missing_column() {
1204 let registry = ResultMapRegistry::new();
1205 let mut rm = ResultMap::new("userMap", "User");
1206 rm.add_id_mapping(Mapping::new("id", "user_id"))
1207 .add_result_mapping(Mapping::new("name", "user_name"));
1208 registry.register(rm);
1209
1210 let row = RowData::empty();
1211 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1212 assert!(!attrs.contains_key("id"));
1214 assert!(!attrs.contains_key("name"));
1215 }
1216
1217 #[test]
1218 fn test_apply_result_map_not_found() {
1219 let registry = ResultMapRegistry::new();
1220 let row = RowData::empty();
1221 let err = apply_result_map(®istry, "missingMap", &row).unwrap_err();
1222 match err {
1223 ResultMapError::MapNotFound { id } => assert_eq!(id, "missingMap"),
1224 _ => panic!("expected MapNotFound"),
1225 }
1226 }
1227
1228 #[test]
1231 fn test_apply_result_map_with_association() {
1232 let registry = ResultMapRegistry::new();
1233
1234 let mut dept_map = ResultMap::new("deptMap", "Dept");
1235 dept_map
1236 .add_id_mapping(Mapping::new("id", "dept_id"))
1237 .add_result_mapping(Mapping::new("name", "dept_name"));
1238 registry.register(dept_map);
1239
1240 let mut user_map = ResultMap::new("userMap", "User");
1241 user_map
1242 .add_id_mapping(Mapping::new("id", "user_id"))
1243 .add_result_mapping(Mapping::new("name", "user_name"))
1244 .add_association(NestedAssociation::new("dept", "deptMap"));
1245 registry.register(user_map);
1246
1247 let mut row = RowData::empty();
1248 row.set("user_id", Value::I64(1));
1249 row.set("user_name", Value::String("Alice".to_string()));
1250 row.set("dept_id", Value::I64(10));
1251 row.set("dept_name", Value::String("Engineering".to_string()));
1252
1253 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1254 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1255 let dept = attrs.get("dept");
1256 assert!(dept.is_some());
1257 if let Some(Value::Object(dept_attrs)) = dept {
1258 assert_eq!(dept_attrs.get("id"), Some(&Value::I64(10)));
1259 assert_eq!(
1260 dept_attrs.get("name"),
1261 Some(&Value::String("Engineering".to_string()))
1262 );
1263 }
1264 }
1265
1266 #[test]
1267 fn test_apply_result_map_association_not_null_column_skip() {
1268 let registry = ResultMapRegistry::new();
1269
1270 let mut dept_map = ResultMap::new("deptMap", "Dept");
1271 dept_map
1272 .add_id_mapping(Mapping::new("id", "dept_id"))
1273 .add_result_mapping(Mapping::new("name", "dept_name"));
1274 registry.register(dept_map);
1275
1276 let mut user_map = ResultMap::new("userMap", "User");
1277 user_map
1278 .add_id_mapping(Mapping::new("id", "user_id"))
1279 .add_result_mapping(Mapping::new("name", "user_name"))
1280 .add_association(
1281 NestedAssociation::new("dept", "deptMap").with_not_null_column("dept_id"),
1282 );
1283 registry.register(user_map);
1284
1285 let mut row = RowData::empty();
1287 row.set("user_id", Value::I64(1));
1288 row.set("user_name", Value::String("Alice".to_string()));
1289 row.set("dept_id", Value::Null);
1290
1291 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1292 assert!(!attrs.contains_key("dept"));
1294 }
1295
1296 #[test]
1297 fn test_apply_result_map_association_with_prefix() {
1298 let registry = ResultMapRegistry::new();
1299
1300 let mut dept_map = ResultMap::new("deptMap", "Dept");
1301 dept_map
1302 .add_id_mapping(Mapping::new("id", "id"))
1303 .add_result_mapping(Mapping::new("name", "name"));
1304 registry.register(dept_map);
1305
1306 let mut user_map = ResultMap::new("userMap", "User");
1307 user_map
1308 .add_id_mapping(Mapping::new("id", "id"))
1309 .add_result_mapping(Mapping::new("name", "name"))
1310 .add_association(NestedAssociation::new("dept", "deptMap").with_prefix("d_"));
1311 registry.register(user_map);
1312
1313 let mut row = RowData::empty();
1315 row.set("id", Value::I64(1));
1316 row.set("name", Value::String("Alice".to_string()));
1317 row.set("d_id", Value::I64(10));
1318 row.set("d_name", Value::String("Engineering".to_string()));
1319
1320 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1321 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1322 assert_eq!(attrs.get("name"), Some(&Value::String("Alice".to_string())));
1323
1324 if let Some(Value::Object(dept_attrs)) = attrs.get("dept") {
1325 assert_eq!(dept_attrs.get("id"), Some(&Value::I64(10)));
1326 assert_eq!(
1327 dept_attrs.get("name"),
1328 Some(&Value::String("Engineering".to_string()))
1329 );
1330 } else {
1331 panic!("dept should be an Object");
1332 }
1333 }
1334
1335 #[test]
1338 fn test_apply_result_map_discriminator() {
1339 let registry = ResultMapRegistry::new();
1340
1341 let mut admin_map = ResultMap::new("adminMap", "AdminUser");
1343 admin_map
1344 .add_id_mapping(Mapping::new("id", "user_id"))
1345 .add_result_mapping(Mapping::new("name", "user_name"))
1346 .add_result_mapping(Mapping::new("admin_level", "extra_level"));
1347 registry.register(admin_map);
1348
1349 let mut normal_map = ResultMap::new("normalMap", "NormalUser");
1351 normal_map
1352 .add_id_mapping(Mapping::new("id", "user_id"))
1353 .add_result_mapping(Mapping::new("name", "user_name"));
1354 registry.register(normal_map);
1355
1356 let mut base_map = ResultMap::new("baseMap", "User");
1358 base_map
1359 .add_id_mapping(Mapping::new("id", "user_id"))
1360 .add_result_mapping(Mapping::new("name", "user_name"))
1361 .set_discriminator({
1362 let mut d = Discriminator::new("user_type");
1363 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1364 d.add_case(DiscriminatorCase::new(Value::I64(2), "normalMap"));
1365 d
1366 });
1367 registry.register(base_map);
1368
1369 let mut row = RowData::empty();
1371 row.set("user_id", Value::I64(1));
1372 row.set("user_name", Value::String("Alice".to_string()));
1373 row.set("user_type", Value::I64(1));
1374 row.set("extra_level", Value::I64(5));
1375
1376 let attrs = apply_result_map(®istry, "baseMap", &row).unwrap();
1377 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1378 assert_eq!(attrs.get("admin_level"), Some(&Value::I64(5)));
1379
1380 let mut row2 = RowData::empty();
1382 row2.set("user_id", Value::I64(2));
1383 row2.set("user_name", Value::String("Bob".to_string()));
1384 row2.set("user_type", Value::I64(2));
1385
1386 let attrs2 = apply_result_map(®istry, "baseMap", &row2).unwrap();
1387 assert_eq!(attrs2.get("id"), Some(&Value::I64(2)));
1388 assert!(!attrs2.contains_key("admin_level")); }
1390
1391 #[test]
1392 fn test_apply_result_map_discriminator_no_match_falls_back_to_base() {
1393 let registry = ResultMapRegistry::new();
1394
1395 let mut base_map = ResultMap::new("baseMap", "User");
1396 base_map
1397 .add_id_mapping(Mapping::new("id", "user_id"))
1398 .set_discriminator({
1399 let mut d = Discriminator::new("user_type");
1400 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1401 d
1402 });
1403 registry.register(base_map);
1404
1405 let mut row = RowData::empty();
1407 row.set("user_id", Value::I64(1));
1408 row.set("user_type", Value::I64(99));
1409
1410 let attrs = apply_result_map(®istry, "baseMap", &row).unwrap();
1411 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1412 }
1413
1414 #[test]
1417 fn test_apply_result_map_many_collection_aggregation() {
1418 let registry = ResultMapRegistry::new();
1419
1420 let mut role_map = ResultMap::new("roleMap", "Role");
1421 role_map
1422 .add_id_mapping(Mapping::new("id", "role_id"))
1423 .add_result_mapping(Mapping::new("name", "role_name"));
1424 registry.register(role_map);
1425
1426 let mut user_map = ResultMap::new("userMap", "User");
1427 user_map
1428 .add_id_mapping(Mapping::new("id", "user_id"))
1429 .add_result_mapping(Mapping::new("name", "user_name"))
1430 .add_collection(NestedCollection::new("roles", "roleMap"));
1431 registry.register(user_map);
1432
1433 let rows = vec![
1435 {
1436 let mut r = RowData::empty();
1437 r.set("user_id", Value::I64(1));
1438 r.set("user_name", Value::String("Alice".to_string()));
1439 r.set("role_id", Value::I64(100));
1440 r.set("role_name", Value::String("admin".to_string()));
1441 r
1442 },
1443 {
1444 let mut r = RowData::empty();
1445 r.set("user_id", Value::I64(1));
1446 r.set("user_name", Value::String("Alice".to_string()));
1447 r.set("role_id", Value::I64(101));
1448 r.set("role_name", Value::String("editor".to_string()));
1449 r
1450 },
1451 ];
1452
1453 let result = apply_result_map_many(®istry, "userMap", &rows).unwrap();
1454 assert_eq!(result.len(), 1); let user = &result[0];
1456 assert_eq!(user.get("id"), Some(&Value::I64(1)));
1457 let roles = user.get("roles");
1458 assert!(roles.is_some());
1459 if let Some(Value::Array(items)) = roles {
1460 assert_eq!(items.len(), 2);
1461 }
1462 }
1463
1464 #[test]
1465 fn test_apply_result_map_many_multi_users() {
1466 let registry = ResultMapRegistry::new();
1467
1468 let mut role_map = ResultMap::new("roleMap", "Role");
1469 role_map
1470 .add_id_mapping(Mapping::new("id", "role_id"))
1471 .add_result_mapping(Mapping::new("name", "role_name"));
1472 registry.register(role_map);
1473
1474 let mut user_map = ResultMap::new("userMap", "User");
1475 user_map
1476 .add_id_mapping(Mapping::new("id", "user_id"))
1477 .add_result_mapping(Mapping::new("name", "user_name"))
1478 .add_collection(NestedCollection::new("roles", "roleMap"));
1479 registry.register(user_map);
1480
1481 let rows = vec![
1482 {
1483 let mut r = RowData::empty();
1484 r.set("user_id", Value::I64(1));
1485 r.set("user_name", Value::String("Alice".to_string()));
1486 r.set("role_id", Value::I64(100));
1487 r.set("role_name", Value::String("admin".to_string()));
1488 r
1489 },
1490 {
1491 let mut r = RowData::empty();
1492 r.set("user_id", Value::I64(2));
1493 r.set("user_name", Value::String("Bob".to_string()));
1494 r.set("role_id", Value::I64(101));
1495 r.set("role_name", Value::String("editor".to_string()));
1496 r
1497 },
1498 ];
1499
1500 let result = apply_result_map_many(®istry, "userMap", &rows).unwrap();
1501 assert_eq!(result.len(), 2);
1502 assert_eq!(result[0].get("id"), Some(&Value::I64(1)));
1504 assert_eq!(result[1].get("id"), Some(&Value::I64(2)));
1505 }
1506
1507 #[test]
1508 fn test_apply_result_map_many_empty() {
1509 let registry = ResultMapRegistry::new();
1510 registry.register(ResultMap::new("userMap", "User"));
1511
1512 let result = apply_result_map_many(®istry, "userMap", &[]).unwrap();
1513 assert!(result.is_empty());
1514 }
1515
1516 #[test]
1519 fn test_entity_result_new() {
1520 let er = EntityResult::new("User");
1521 assert_eq!(er.entity_class, "User");
1522 assert!(er.fields.is_empty());
1523 assert_eq!(er.discriminator_column, None);
1524 }
1525
1526 #[test]
1527 fn test_entity_result_add_field() {
1528 let mut er = EntityResult::new("User");
1529 er.add_field(FieldResult::new("id", "user_id"))
1530 .add_field(FieldResult::new("name", "user_name"));
1531 assert_eq!(er.fields.len(), 2);
1532 }
1533
1534 #[test]
1535 fn test_entity_result_with_discriminator() {
1536 let er = EntityResult::new("User").with_discriminator_column("user_type");
1537 assert_eq!(er.discriminator_column.as_deref(), Some("user_type"));
1538 }
1539
1540 #[test]
1541 fn test_scalar_result_new() {
1542 let s = ScalarResult::new("count", "i64");
1543 assert_eq!(s.column, "count");
1544 assert_eq!(s.type_name, "i64");
1545 }
1546
1547 #[test]
1548 fn test_result_set_mapping_new() {
1549 let rsm = ResultSetMapping::new("userCount");
1550 assert_eq!(rsm.name, "userCount");
1551 assert!(rsm.entities.is_empty());
1552 assert!(rsm.scalars.is_empty());
1553 }
1554
1555 #[test]
1556 fn test_result_set_mapping_add() {
1557 let mut rsm = ResultSetMapping::new("userWithCount");
1558 rsm.add_entity(EntityResult::new("User"))
1559 .add_scalar(ScalarResult::new("total", "i64"));
1560 assert_eq!(rsm.entities.len(), 1);
1561 assert_eq!(rsm.scalars.len(), 1);
1562 }
1563
1564 #[test]
1567 fn test_rsm_registry() {
1568 let reg = ResultSetMappingRegistry::new();
1569 reg.register(ResultSetMapping::new("mapping1"));
1570 assert!(reg.contains("mapping1"));
1571 assert!(!reg.contains("missing"));
1572 assert_eq!(reg.len(), 1);
1573 assert!(reg.get("mapping1").is_some());
1574 assert!(reg.get("missing").is_none());
1575 }
1576
1577 #[test]
1580 fn test_native_query_new() {
1581 let nq = NativeQuery::new("SELECT * FROM users WHERE id = ?", "userMapping");
1582 assert_eq!(nq.sql, "SELECT * FROM users WHERE id = ?");
1583 assert_eq!(nq.result_set_mapping, "userMapping");
1584 assert!(nq.parameters.is_empty());
1585 }
1586
1587 #[test]
1588 fn test_native_query_bind() {
1589 let mut nq = NativeQuery::new("SELECT * FROM users WHERE id = ?", "userMapping");
1590 nq.bind(Value::I64(1));
1591 assert_eq!(nq.parameters.len(), 1);
1592 assert_eq!(nq.parameters[0], Value::I64(1));
1593 }
1594
1595 #[test]
1596 fn test_native_query_bind_many() {
1597 let mut nq = NativeQuery::new("SELECT * FROM users WHERE id IN (?, ?)", "userMapping");
1598 nq.bind_many(vec![Value::I64(1), Value::I64(2)]);
1599 assert_eq!(nq.parameters.len(), 2);
1600 }
1601
1602 #[test]
1605 fn test_apply_result_set_mapping_entities_only() {
1606 let mut rsm = ResultSetMapping::new("userMapping");
1607 let mut er = EntityResult::new("User");
1608 er.add_field(FieldResult::new("id", "user_id"))
1609 .add_field(FieldResult::new("name", "user_name"));
1610 rsm.add_entity(er);
1611
1612 let mut row = RowData::empty();
1613 row.set("user_id", Value::I64(1));
1614 row.set("user_name", Value::String("Alice".to_string()));
1615
1616 let (entities, scalars) = apply_result_set_mapping(&rsm, &row);
1617 assert_eq!(entities.len(), 1);
1618 assert_eq!(entities[0].get("id"), Some(&Value::I64(1)));
1619 assert_eq!(
1620 entities[0].get("name"),
1621 Some(&Value::String("Alice".to_string()))
1622 );
1623 assert!(scalars.is_empty());
1624 }
1625
1626 #[test]
1627 fn test_apply_result_set_mapping_scalars_only() {
1628 let mut rsm = ResultSetMapping::new("countMapping");
1629 rsm.add_scalar(ScalarResult::new("total", "i64"))
1630 .add_scalar(ScalarResult::new("avg_age", "f64"));
1631
1632 let mut row = RowData::empty();
1633 row.set("total", Value::I64(100));
1634 row.set("avg_age", Value::F64(25.5));
1635
1636 let (entities, scalars) = apply_result_set_mapping(&rsm, &row);
1637 assert!(entities.is_empty());
1638 assert_eq!(scalars.len(), 2);
1639 assert_eq!(scalars[0], Value::I64(100));
1640 assert_eq!(scalars[1], Value::F64(25.5));
1641 }
1642
1643 #[test]
1644 fn test_apply_result_set_mapping_mixed() {
1645 let mut rsm = ResultSetMapping::new("userWithCount");
1646 let mut er = EntityResult::new("User");
1647 er.add_field(FieldResult::new("id", "user_id"))
1648 .add_field(FieldResult::new("name", "user_name"));
1649 rsm.add_entity(er);
1650 rsm.add_scalar(ScalarResult::new("total_orders", "i64"));
1651
1652 let mut row = RowData::empty();
1653 row.set("user_id", Value::I64(1));
1654 row.set("user_name", Value::String("Alice".to_string()));
1655 row.set("total_orders", Value::I64(42));
1656
1657 let (entities, scalars) = apply_result_set_mapping(&rsm, &row);
1658 assert_eq!(entities.len(), 1);
1659 assert_eq!(scalars.len(), 1);
1660 assert_eq!(entities[0].get("id"), Some(&Value::I64(1)));
1661 assert_eq!(scalars[0], Value::I64(42));
1662 }
1663
1664 #[test]
1665 fn test_apply_result_set_mapping_many() {
1666 let mut rsm = ResultSetMapping::new("userMapping");
1667 let mut er = EntityResult::new("User");
1668 er.add_field(FieldResult::new("id", "user_id"));
1669 rsm.add_entity(er);
1670
1671 let rows = vec![
1672 {
1673 let mut r = RowData::empty();
1674 r.set("user_id", Value::I64(1));
1675 r
1676 },
1677 {
1678 let mut r = RowData::empty();
1679 r.set("user_id", Value::I64(2));
1680 r
1681 },
1682 ];
1683
1684 let results = apply_result_set_mapping_many(&rsm, &rows);
1685 assert_eq!(results.len(), 2);
1686 assert_eq!(results[0].0[0].get("id"), Some(&Value::I64(1)));
1687 assert_eq!(results[1].0[0].get("id"), Some(&Value::I64(2)));
1688 }
1689
1690 #[test]
1693 fn test_e2e_user_with_dept_and_roles() {
1694 let registry = ResultMapRegistry::new();
1695
1696 let mut role_map = ResultMap::new("roleMap", "Role");
1698 role_map
1699 .add_id_mapping(Mapping::new("id", "role_id"))
1700 .add_result_mapping(Mapping::new("name", "role_name"));
1701 registry.register(role_map);
1702
1703 let mut dept_map = ResultMap::new("deptMap", "Dept");
1705 dept_map
1706 .add_id_mapping(Mapping::new("id", "dept_id"))
1707 .add_result_mapping(Mapping::new("name", "dept_name"));
1708 registry.register(dept_map);
1709
1710 let mut user_map = ResultMap::new("userMap", "User");
1712 user_map
1713 .add_id_mapping(Mapping::new("id", "user_id"))
1714 .add_result_mapping(Mapping::new("name", "user_name"))
1715 .add_association(NestedAssociation::new("dept", "deptMap"))
1716 .add_collection(NestedCollection::new("roles", "roleMap"));
1717 registry.register(user_map);
1718
1719 let rows = vec![
1721 {
1722 let mut r = RowData::empty();
1723 r.set("user_id", Value::I64(1));
1724 r.set("user_name", Value::String("Alice".to_string()));
1725 r.set("dept_id", Value::I64(10));
1726 r.set("dept_name", Value::String("Engineering".to_string()));
1727 r.set("role_id", Value::I64(100));
1728 r.set("role_name", Value::String("admin".to_string()));
1729 r
1730 },
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(101));
1738 r.set("role_name", Value::String("editor".to_string()));
1739 r
1740 },
1741 ];
1742
1743 let result = apply_result_map_many(®istry, "userMap", &rows).unwrap();
1744 assert_eq!(result.len(), 1);
1745 let user = &result[0];
1746 assert_eq!(user.get("id"), Some(&Value::I64(1)));
1747 assert_eq!(user.get("name"), Some(&Value::String("Alice".to_string())));
1748
1749 if let Some(Value::Object(dept_attrs)) = user.get("dept") {
1751 assert_eq!(dept_attrs.get("id"), Some(&Value::I64(10)));
1752 assert_eq!(
1753 dept_attrs.get("name"),
1754 Some(&Value::String("Engineering".to_string()))
1755 );
1756 } else {
1757 panic!("dept should be an Object");
1758 }
1759
1760 if let Some(Value::Array(roles)) = user.get("roles") {
1762 assert_eq!(roles.len(), 2);
1763 } else {
1764 panic!("roles should be an Array");
1765 }
1766 }
1767
1768 #[test]
1769 fn test_e2e_native_query_with_rsm() {
1770 let mut rsm = ResultSetMapping::new("userOrderCount");
1774 let mut er = EntityResult::new("User");
1775 er.add_field(FieldResult::new("id", "user_id"))
1776 .add_field(FieldResult::new("name", "user_name"));
1777 rsm.add_entity(er);
1778 rsm.add_scalar(ScalarResult::new("order_count", "i64"));
1779
1780 let mut nq = NativeQuery::new(
1781 "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",
1782 "userOrderCount",
1783 );
1784 nq.bind(Value::Null); let rows = vec![
1788 {
1789 let mut r = RowData::empty();
1790 r.set("user_id", Value::I64(1));
1791 r.set("user_name", Value::String("Alice".to_string()));
1792 r.set("order_count", Value::I64(5));
1793 r
1794 },
1795 {
1796 let mut r = RowData::empty();
1797 r.set("user_id", Value::I64(2));
1798 r.set("user_name", Value::String("Bob".to_string()));
1799 r.set("order_count", Value::I64(3));
1800 r
1801 },
1802 ];
1803
1804 let reg = ResultSetMappingRegistry::new();
1805 reg.register(rsm.clone());
1806 assert!(reg.contains("userOrderCount"));
1807
1808 let results = apply_result_set_mapping_many(&rsm, &rows);
1809 assert_eq!(results.len(), 2);
1810 assert_eq!(results[0].0[0].get("id"), Some(&Value::I64(1)));
1811 assert_eq!(results[0].1[0], Value::I64(5));
1812 assert_eq!(results[1].0[0].get("id"), Some(&Value::I64(2)));
1813 assert_eq!(results[1].1[0], Value::I64(3));
1814
1815 assert_eq!(nq.result_set_mapping, "userOrderCount");
1817 assert_eq!(nq.parameters.len(), 1);
1818 }
1819}