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