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 {
477 id: String,
479 },
480 RequiredColumnMissing {
482 column: String,
484 },
485 NestedMappingFailed {
487 property: String,
489 reason: String,
491 },
492}
493
494impl std::fmt::Display for ResultMapError {
495 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
496 match self {
497 ResultMapError::MapNotFound { id } => {
498 write!(f, "ResultMap '{}' not registered", id)
499 }
500 ResultMapError::RequiredColumnMissing { column } => {
501 write!(f, "Required column '{}' missing in row", column)
502 }
503 ResultMapError::NestedMappingFailed { property, reason } => {
504 write!(f, "Nested mapping failed for '{}': {}", property, reason)
505 }
506 }
507 }
508}
509
510impl std::error::Error for ResultMapError {}
511
512#[tracing::instrument(skip(registry, row), fields(map_id = map_id))]
525pub fn apply_result_map(
526 registry: &ResultMapRegistry,
527 map_id: &str,
528 row: &RowData,
529) -> Result<HashMap<String, Value>, ResultMapError> {
530 let map = registry
531 .get(map_id)
532 .ok_or_else(|| ResultMapError::MapNotFound {
533 id: map_id.to_string(),
534 })?;
535
536 let effective_map = if let Some(disc) = &map.discriminator {
538 if let Some(disc_value) = row.get(&disc.column) {
539 if let Some(case_map_id) = disc.resolve(disc_value) {
540 registry.get(case_map_id).unwrap_or(map)
541 } else {
542 map
543 }
544 } else {
545 map
546 }
547 } else {
548 map
549 };
550
551 let mut attrs: HashMap<String, Value> = HashMap::new();
552
553 for m in &effective_map.id_mappings {
555 if let Some(v) = row.get(&m.column) {
556 attrs.insert(m.property.clone(), v.clone());
557 }
558 }
559 for m in &effective_map.result_mappings {
560 if let Some(v) = row.get(&m.column) {
561 attrs.insert(m.property.clone(), v.clone());
562 }
563 }
564
565 for assoc in &effective_map.associations {
567 if let Some(not_null_col) = &assoc.not_null_column {
569 if !row.is_not_null(not_null_col) {
570 continue; }
572 }
573
574 let nested_value = if let Some(prefix) = &assoc.column_prefix {
576 let mut prefixed_row = RowData::empty();
578 for (col, v) in &row.columns {
579 if let Some(stripped) = col.strip_prefix(prefix) {
580 prefixed_row.set(stripped.to_string(), v.clone());
581 }
582 }
583 apply_result_map(registry, &assoc.result_map, &prefixed_row).map_err(|e| {
584 ResultMapError::NestedMappingFailed {
585 property: assoc.property.clone(),
586 reason: e.to_string(),
587 }
588 })?
589 } else {
590 apply_result_map(registry, &assoc.result_map, row).map_err(|e| {
592 ResultMapError::NestedMappingFailed {
593 property: assoc.property.clone(),
594 reason: e.to_string(),
595 }
596 })?
597 };
598
599 attrs.insert(assoc.property.clone(), Value::Object(nested_value));
601 }
602
603 for coll in &effective_map.collections {
605 if let Some(not_null_col) = &coll.not_null_column {
606 if !row.is_not_null(not_null_col) {
607 continue;
608 }
609 }
610
611 let nested = if let Some(prefix) = &coll.column_prefix {
612 let mut prefixed_row = RowData::empty();
613 for (col, v) in &row.columns {
614 if let Some(stripped) = col.strip_prefix(prefix) {
615 prefixed_row.set(stripped.to_string(), v.clone());
616 }
617 }
618 apply_result_map(registry, &coll.result_map, &prefixed_row).map_err(|e| {
619 ResultMapError::NestedMappingFailed {
620 property: coll.property.clone(),
621 reason: e.to_string(),
622 }
623 })?
624 } else {
625 apply_result_map(registry, &coll.result_map, row).map_err(|e| {
626 ResultMapError::NestedMappingFailed {
627 property: coll.property.clone(),
628 reason: e.to_string(),
629 }
630 })?
631 };
632
633 attrs.insert(
636 coll.property.clone(),
637 Value::Array(vec![Value::Object(nested)]),
638 );
639 }
640
641 Ok(attrs)
642}
643
644#[tracing::instrument(skip(registry, rows), fields(map_id = map_id, row_count = rows.len()))]
652pub fn apply_result_map_many(
653 registry: &ResultMapRegistry,
654 map_id: &str,
655 rows: &[RowData],
656) -> Result<Vec<HashMap<String, Value>>, ResultMapError> {
657 if rows.is_empty() {
658 return Ok(Vec::new());
659 }
660
661 let map = registry
662 .get(map_id)
663 .ok_or_else(|| ResultMapError::MapNotFound {
664 id: map_id.to_string(),
665 })?;
666
667 fn pk_key(attrs: &HashMap<String, Value>, id_mappings: &[Mapping]) -> String {
669 if id_mappings.is_empty() {
670 return String::new();
673 }
674 let mut parts = Vec::new();
675 for m in id_mappings {
676 if let Some(v) = attrs.get(&m.property) {
677 parts.push(format!("{:?}", v));
678 } else {
679 parts.push("null".to_string());
680 }
681 }
682 parts.join("|")
683 }
684
685 let mut ordered_keys: Vec<String> = Vec::new();
687 let mut groups: HashMap<String, HashMap<String, Value>> = HashMap::new();
688 let mut collection_acc: HashMap<String, HashMap<String, Vec<Value>>> = HashMap::new();
689
690 for row in rows {
691 let attrs = apply_result_map(registry, map_id, row)?;
692 let key = pk_key(&attrs, &map.id_mappings);
693
694 if !groups.contains_key(&key) {
695 ordered_keys.push(key.clone());
696 groups.insert(key.clone(), attrs.clone());
697 collection_acc.insert(key.clone(), HashMap::new());
698 }
699
700 for coll in &map.collections {
702 if let Some(Value::Array(items)) = attrs.get(&coll.property) {
703 if !items.is_empty() {
704 let acc = collection_acc.get_mut(&key).ok_or_else(|| {
705 ResultMapError::NestedMappingFailed {
706 property: "collection_acc".to_string(),
707 reason: format!("key '{}' not found in collection_acc", key),
708 }
709 })?;
710 let entry = acc.entry(coll.property.clone()).or_default();
711 for item in items {
712 entry.push(item.clone());
713 }
714 }
715 }
716 }
717 }
718
719 let mut result = Vec::new();
721 for key in ordered_keys {
722 let mut attrs = groups
723 .remove(&key)
724 .ok_or_else(|| ResultMapError::NestedMappingFailed {
725 property: "groups".to_string(),
726 reason: format!("key '{}' not found in groups", key),
727 })?;
728 if let Some(coll_acc) = collection_acc.remove(&key) {
729 for (prop, items) in coll_acc {
730 attrs.insert(prop, Value::Array(items));
731 }
732 }
733 result.push(attrs);
734 }
735
736 Ok(result)
737}
738
739#[cfg(feature = "zero-copy")]
744mod borrowed {
745 use super::*;
746 use crate::value_borrowed::{BorrowedRowData, BorrowedValue};
747
748 #[tracing::instrument(skip(registry, row), fields(map_id = map_id))]
753 pub fn apply_result_map_borrowed<'a>(
754 registry: &ResultMapRegistry,
755 map_id: &str,
756 row: &BorrowedRowData<'a>,
757 ) -> Result<HashMap<String, BorrowedValue<'a>>, ResultMapError> {
758 let map = registry
759 .get(map_id)
760 .ok_or_else(|| ResultMapError::MapNotFound {
761 id: map_id.to_string(),
762 })?;
763
764 let effective_map = if let Some(disc) = &map.discriminator {
765 if let Some(disc_value) = row.get(&disc.column) {
766 let owned_disc = disc_value.to_owned_value();
767 if let Some(case_map_id) = disc.resolve(&owned_disc) {
768 registry.get(case_map_id).unwrap_or(map)
769 } else {
770 map
771 }
772 } else {
773 map
774 }
775 } else {
776 map
777 };
778
779 let mut attrs: HashMap<String, BorrowedValue<'a>> = HashMap::new();
780
781 for m in &effective_map.id_mappings {
782 if let Some(v) = row.get(&m.column) {
783 attrs.insert(m.property.clone(), v.clone());
784 }
785 }
786 for m in &effective_map.result_mappings {
787 if let Some(v) = row.get(&m.column) {
788 attrs.insert(m.property.clone(), v.clone());
789 }
790 }
791
792 for assoc in &effective_map.associations {
793 if let Some(not_null_col) = &assoc.not_null_column {
794 if !row.is_not_null(not_null_col) {
795 continue;
796 }
797 }
798
799 let nested_value = if let Some(prefix) = &assoc.column_prefix {
800 let mut prefixed_row = BorrowedRowData::new();
801 for (col, v) in row.iter() {
802 if let Some(stripped) = col.strip_prefix(prefix) {
803 prefixed_row.set(stripped.to_string(), v.clone());
804 }
805 }
806 apply_result_map_borrowed(registry, &assoc.result_map, &prefixed_row).map_err(
807 |e| ResultMapError::NestedMappingFailed {
808 property: assoc.property.clone(),
809 reason: e.to_string(),
810 },
811 )?
812 } else {
813 apply_result_map_borrowed(registry, &assoc.result_map, row).map_err(|e| {
814 ResultMapError::NestedMappingFailed {
815 property: assoc.property.clone(),
816 reason: e.to_string(),
817 }
818 })?
819 };
820
821 attrs.insert(assoc.property.clone(), BorrowedValue::Object(nested_value));
822 }
823
824 for coll in &effective_map.collections {
825 if let Some(not_null_col) = &coll.not_null_column {
826 if !row.is_not_null(not_null_col) {
827 continue;
828 }
829 }
830
831 let nested = if let Some(prefix) = &coll.column_prefix {
832 let mut prefixed_row = BorrowedRowData::new();
833 for (col, v) in row.iter() {
834 if let Some(stripped) = col.strip_prefix(prefix) {
835 prefixed_row.set(stripped.to_string(), v.clone());
836 }
837 }
838 apply_result_map_borrowed(registry, &coll.result_map, &prefixed_row).map_err(
839 |e| ResultMapError::NestedMappingFailed {
840 property: coll.property.clone(),
841 reason: e.to_string(),
842 },
843 )?
844 } else {
845 apply_result_map_borrowed(registry, &coll.result_map, row).map_err(|e| {
846 ResultMapError::NestedMappingFailed {
847 property: coll.property.clone(),
848 reason: e.to_string(),
849 }
850 })?
851 };
852
853 attrs.insert(
854 coll.property.clone(),
855 BorrowedValue::Array(vec![BorrowedValue::Object(nested)]),
856 );
857 }
858
859 Ok(attrs)
860 }
861
862 #[tracing::instrument(skip(registry, rows), fields(map_id = map_id, row_count = rows.len()))]
866 pub fn apply_result_map_many_borrowed<'a>(
867 registry: &ResultMapRegistry,
868 map_id: &str,
869 rows: &[BorrowedRowData<'a>],
870 ) -> Result<Vec<HashMap<String, BorrowedValue<'a>>>, ResultMapError> {
871 if rows.is_empty() {
872 return Ok(Vec::new());
873 }
874
875 let map = registry
876 .get(map_id)
877 .ok_or_else(|| ResultMapError::MapNotFound {
878 id: map_id.to_string(),
879 })?;
880
881 fn pk_key_borrowed(
882 attrs: &HashMap<String, BorrowedValue<'_>>,
883 id_mappings: &[Mapping],
884 ) -> String {
885 if id_mappings.is_empty() {
886 return String::new();
887 }
888 let mut parts = Vec::new();
889 for m in id_mappings {
890 if let Some(v) = attrs.get(&m.property) {
891 parts.push(format!("{:?}", v));
892 } else {
893 parts.push("null".to_string());
894 }
895 }
896 parts.join("|")
897 }
898
899 let mut ordered_keys: Vec<String> = Vec::new();
900 let mut groups: HashMap<String, HashMap<String, BorrowedValue<'a>>> = HashMap::new();
901 let mut collection_acc: HashMap<String, HashMap<String, Vec<BorrowedValue<'a>>>> =
902 HashMap::new();
903
904 for row in rows {
905 let attrs = apply_result_map_borrowed(registry, map_id, row)?;
906 let key = pk_key_borrowed(&attrs, &map.id_mappings);
907
908 if !groups.contains_key(&key) {
909 ordered_keys.push(key.clone());
910 groups.insert(key.clone(), attrs.clone());
911 collection_acc.insert(key.clone(), HashMap::new());
912 }
913
914 for coll in &map.collections {
915 if let Some(BorrowedValue::Array(items)) = attrs.get(&coll.property) {
916 if !items.is_empty() {
917 let acc = collection_acc.get_mut(&key).ok_or_else(|| {
918 ResultMapError::NestedMappingFailed {
919 property: "collection_acc".to_string(),
920 reason: format!("key '{}' not found in collection_acc", key),
921 }
922 })?;
923 let entry = acc.entry(coll.property.clone()).or_default();
924 for item in items {
925 entry.push(item.clone());
926 }
927 }
928 }
929 }
930 }
931
932 let mut result = Vec::new();
933 for key in ordered_keys {
934 let mut attrs =
935 groups
936 .remove(&key)
937 .ok_or_else(|| ResultMapError::NestedMappingFailed {
938 property: "groups".to_string(),
939 reason: format!("key '{}' not found in groups", key),
940 })?;
941 if let Some(coll_acc) = collection_acc.remove(&key) {
942 for (prop, items) in coll_acc {
943 attrs.insert(prop, BorrowedValue::Array(items));
944 }
945 }
946 result.push(attrs);
947 }
948
949 Ok(result)
950 }
951}
952
953#[cfg(feature = "zero-copy")]
954pub use borrowed::{apply_result_map_borrowed, apply_result_map_many_borrowed};
955
956#[derive(Debug, Clone, PartialEq, Eq)]
958pub struct ScalarResult {
959 pub column: String,
961 pub type_name: String,
963}
964
965impl ScalarResult {
966 pub fn new(column: impl Into<String>, type_name: impl Into<String>) -> Self {
968 Self {
969 column: column.into(),
970 type_name: type_name.into(),
971 }
972 }
973}
974
975#[derive(Debug, Clone, PartialEq, Eq)]
977pub struct FieldResult {
978 pub name: String,
980 pub column: String,
982}
983
984impl FieldResult {
985 pub fn new(name: impl Into<String>, column: impl Into<String>) -> Self {
987 Self {
988 name: name.into(),
989 column: column.into(),
990 }
991 }
992}
993
994#[derive(Debug, Clone, PartialEq, Eq)]
996pub struct EntityResult {
997 pub entity_class: String,
999 pub fields: Vec<FieldResult>,
1001 pub discriminator_column: Option<String>,
1003}
1004
1005impl EntityResult {
1006 pub fn new(entity_class: impl Into<String>) -> Self {
1008 Self {
1009 entity_class: entity_class.into(),
1010 fields: Vec::new(),
1011 discriminator_column: None,
1012 }
1013 }
1014
1015 pub fn add_field(&mut self, field: FieldResult) -> &mut Self {
1017 self.fields.push(field);
1018 self
1019 }
1020
1021 pub fn with_discriminator_column(mut self, col: impl Into<String>) -> Self {
1023 self.discriminator_column = Some(col.into());
1024 self
1025 }
1026}
1027
1028#[derive(Debug, Clone, PartialEq)]
1030pub struct ResultSetMapping {
1031 pub name: String,
1033 pub entities: Vec<EntityResult>,
1035 pub scalars: Vec<ScalarResult>,
1037}
1038
1039impl ResultSetMapping {
1040 pub fn new(name: impl Into<String>) -> Self {
1042 Self {
1043 name: name.into(),
1044 entities: Vec::new(),
1045 scalars: Vec::new(),
1046 }
1047 }
1048
1049 pub fn add_entity(&mut self, entity: EntityResult) -> &mut Self {
1051 self.entities.push(entity);
1052 self
1053 }
1054
1055 pub fn add_scalar(&mut self, scalar: ScalarResult) -> &mut Self {
1057 self.scalars.push(scalar);
1058 self
1059 }
1060}
1061
1062#[derive(Debug, Default)]
1064pub struct ResultSetMappingRegistry {
1065 mappings: RwLock<HashMap<String, ResultSetMapping>>,
1066}
1067
1068impl ResultSetMappingRegistry {
1069 pub fn new() -> Self {
1071 Self {
1072 mappings: RwLock::new(HashMap::new()),
1073 }
1074 }
1075
1076 pub fn register(&self, mapping: ResultSetMapping) {
1078 let mut m = self.mappings.write();
1079 m.insert(mapping.name.clone(), mapping);
1080 }
1081
1082 pub fn get(&self, name: &str) -> Option<ResultSetMapping> {
1084 let m = self.mappings.read();
1085 m.get(name).cloned()
1086 }
1087
1088 pub fn contains(&self, name: &str) -> bool {
1090 let m = self.mappings.read();
1091 m.contains_key(name)
1092 }
1093
1094 pub fn len(&self) -> usize {
1096 let m = self.mappings.read();
1097 m.len()
1098 }
1099
1100 pub fn is_empty(&self) -> bool {
1102 self.len() == 0
1103 }
1104}
1105
1106#[derive(Debug, Clone)]
1112pub struct NativeQuery {
1113 pub sql: String,
1115 pub result_set_mapping: String,
1117 pub parameters: Vec<Value>,
1119}
1120
1121impl NativeQuery {
1122 pub fn new(sql: impl Into<String>, mapping_name: impl Into<String>) -> Self {
1124 Self {
1125 sql: sql.into(),
1126 result_set_mapping: mapping_name.into(),
1127 parameters: Vec::new(),
1128 }
1129 }
1130
1131 pub fn bind(&mut self, value: Value) -> &mut Self {
1133 self.parameters.push(value);
1134 self
1135 }
1136
1137 pub fn bind_many(&mut self, values: Vec<Value>) -> &mut Self {
1139 self.parameters.extend(values);
1140 self
1141 }
1142}
1143
1144pub fn apply_result_set_mapping(
1150 mapping: &ResultSetMapping,
1151 row: &RowData,
1152) -> ResultSetMappingResult {
1153 let mut entities = Vec::new();
1154 for ent in &mapping.entities {
1155 let mut attrs = HashMap::new();
1156 for f in &ent.fields {
1157 if let Some(v) = row.get(&f.column) {
1158 attrs.insert(f.name.clone(), v.clone());
1159 }
1160 }
1161 entities.push(attrs);
1162 }
1163
1164 let mut scalars = Vec::new();
1165 for s in &mapping.scalars {
1166 if let Some(v) = row.get(&s.column) {
1167 scalars.push(v.clone());
1168 } else {
1169 scalars.push(Value::Null);
1170 }
1171 }
1172
1173 (entities, scalars)
1174}
1175
1176pub type ResultSetMappingResult = (Vec<HashMap<String, Value>>, Vec<Value>);
1178
1179pub fn apply_result_set_mapping_many(
1181 mapping: &ResultSetMapping,
1182 rows: &[RowData],
1183) -> Vec<ResultSetMappingResult> {
1184 rows.iter()
1185 .map(|row| apply_result_set_mapping(mapping, row))
1186 .collect()
1187}
1188
1189#[cfg(test)]
1194mod tests {
1195 use super::*;
1196
1197 #[test]
1200 fn test_mapping_new() {
1201 let m = Mapping::new("id", "user_id");
1202 assert_eq!(m.property, "id");
1203 assert_eq!(m.column, "user_id");
1204 assert_eq!(m.type_handler, None);
1205 }
1206
1207 #[test]
1208 fn test_mapping_with_handler() {
1209 let m = Mapping::with_handler("amount", "amount", "money_handler");
1210 assert_eq!(m.property, "amount");
1211 assert_eq!(m.column, "amount");
1212 assert_eq!(m.type_handler.as_deref(), Some("money_handler"));
1213 }
1214
1215 #[test]
1218 fn test_association_new() {
1219 let a = NestedAssociation::new("dept", "deptMap");
1220 assert_eq!(a.property, "dept");
1221 assert_eq!(a.result_map, "deptMap");
1222 assert_eq!(a.column_prefix, None);
1223 assert_eq!(a.not_null_column, None);
1224 }
1225
1226 #[test]
1227 fn test_association_with_prefix() {
1228 let a = NestedAssociation::new("dept", "deptMap").with_prefix("d_");
1229 assert_eq!(a.column_prefix.as_deref(), Some("d_"));
1230 }
1231
1232 #[test]
1233 fn test_association_with_not_null_column() {
1234 let a = NestedAssociation::new("dept", "deptMap").with_not_null_column("dept_id");
1235 assert_eq!(a.not_null_column.as_deref(), Some("dept_id"));
1236 }
1237
1238 #[test]
1241 fn test_collection_new() {
1242 let c = NestedCollection::new("roles", "roleMap");
1243 assert_eq!(c.property, "roles");
1244 assert_eq!(c.result_map, "roleMap");
1245 assert_eq!(c.column_prefix, None);
1246 }
1247
1248 #[test]
1249 fn test_collection_with_prefix() {
1250 let c = NestedCollection::new("roles", "roleMap").with_prefix("r_");
1251 assert_eq!(c.column_prefix.as_deref(), Some("r_"));
1252 }
1253
1254 #[test]
1257 fn test_discriminator_new() {
1258 let d = Discriminator::new("user_type");
1259 assert_eq!(d.column, "user_type");
1260 assert!(d.cases.is_empty());
1261 }
1262
1263 #[test]
1264 fn test_discriminator_add_case() {
1265 let mut d = Discriminator::new("user_type");
1266 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"))
1267 .add_case(DiscriminatorCase::new(Value::I64(2), "userMap"));
1268 assert_eq!(d.cases.len(), 2);
1269 }
1270
1271 #[test]
1272 fn test_discriminator_resolve_hit() {
1273 let mut d = Discriminator::new("user_type");
1274 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"))
1275 .add_case(DiscriminatorCase::new(Value::I64(2), "userMap"));
1276
1277 assert_eq!(d.resolve(&Value::I64(1)), Some("adminMap"));
1278 assert_eq!(d.resolve(&Value::I64(2)), Some("userMap"));
1279 }
1280
1281 #[test]
1282 fn test_discriminator_resolve_miss() {
1283 let mut d = Discriminator::new("user_type");
1284 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1285
1286 assert_eq!(d.resolve(&Value::I64(99)), None);
1287 }
1288
1289 #[test]
1292 fn test_result_map_new() {
1293 let rm = ResultMap::new("userMap", "User");
1294 assert_eq!(rm.id, "userMap");
1295 assert_eq!(rm.type_name, "User");
1296 assert!(rm.id_mappings.is_empty());
1297 assert!(rm.result_mappings.is_empty());
1298 assert!(rm.associations.is_empty());
1299 assert!(rm.collections.is_empty());
1300 assert!(rm.discriminator.is_none());
1301 }
1302
1303 #[test]
1304 fn test_result_map_add_mappings() {
1305 let mut rm = ResultMap::new("userMap", "User");
1306 rm.add_id_mapping(Mapping::new("id", "user_id"))
1307 .add_result_mapping(Mapping::new("name", "user_name"))
1308 .add_association(NestedAssociation::new("dept", "deptMap"))
1309 .add_collection(NestedCollection::new("roles", "roleMap"));
1310
1311 assert_eq!(rm.id_mappings.len(), 1);
1312 assert_eq!(rm.result_mappings.len(), 1);
1313 assert_eq!(rm.associations.len(), 1);
1314 assert_eq!(rm.collections.len(), 1);
1315 }
1316
1317 #[test]
1318 fn test_result_map_set_discriminator() {
1319 let mut rm = ResultMap::new("userMap", "User");
1320 rm.set_discriminator(Discriminator::new("user_type"));
1321 assert!(rm.discriminator.is_some());
1322 assert_eq!(rm.discriminator.as_ref().unwrap().column, "user_type");
1323 }
1324
1325 #[test]
1326 fn test_sub_map_ids() {
1327 let mut rm = ResultMap::new("userMap", "User");
1328 rm.add_association(NestedAssociation::new("dept", "deptMap"))
1329 .add_collection(NestedCollection::new("roles", "roleMap"))
1330 .set_discriminator({
1331 let mut d = Discriminator::new("type");
1332 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1333 d
1334 });
1335
1336 let ids = rm.sub_map_ids();
1337 assert!(ids.contains(&"deptMap".to_string()));
1338 assert!(ids.contains(&"roleMap".to_string()));
1339 assert!(ids.contains(&"adminMap".to_string()));
1340 }
1341
1342 #[test]
1345 fn test_registry_register_and_get() {
1346 let registry = ResultMapRegistry::new();
1347 let rm = ResultMap::new("userMap", "User");
1348 registry.register(rm);
1349
1350 assert!(registry.contains("userMap"));
1351 assert!(!registry.contains("missing"));
1352 assert_eq!(registry.len(), 1);
1353 assert!(registry.get("userMap").is_some());
1354 assert!(registry.get("missing").is_none());
1355 }
1356
1357 #[test]
1358 fn test_registry_list_ids() {
1359 let registry = ResultMapRegistry::new();
1360 registry.register(ResultMap::new("userMap", "User"));
1361 registry.register(ResultMap::new("deptMap", "Dept"));
1362
1363 let ids = registry.list_ids();
1364 assert_eq!(ids.len(), 2);
1365 assert!(ids.contains(&"userMap".to_string()));
1366 assert!(ids.contains(&"deptMap".to_string()));
1367 }
1368
1369 #[test]
1370 fn test_registry_clear() {
1371 let registry = ResultMapRegistry::new();
1372 registry.register(ResultMap::new("userMap", "User"));
1373 assert_eq!(registry.len(), 1);
1374 registry.clear();
1375 assert_eq!(registry.len(), 0);
1376 }
1377
1378 #[test]
1379 fn test_registry_overwrite() {
1380 let registry = ResultMapRegistry::new();
1381 registry.register(ResultMap::new("userMap", "User"));
1382 registry.register(ResultMap::new("userMap", "AdminUser"));
1383
1384 let rm = registry.get("userMap").unwrap();
1385 assert_eq!(rm.type_name, "AdminUser");
1386 }
1387
1388 #[test]
1391 fn test_row_data_new() {
1392 let mut cols = HashMap::new();
1393 cols.insert("id".to_string(), Value::I64(1));
1394 let row = RowData::new(cols);
1395
1396 assert_eq!(row.get("id"), Some(&Value::I64(1)));
1397 assert_eq!(row.get("missing"), None);
1398 assert_eq!(row.len(), 1);
1399 }
1400
1401 #[test]
1402 fn test_row_data_set_and_get() {
1403 let mut row = RowData::empty();
1404 row.set("name", Value::String("Alice".to_string()));
1405
1406 assert_eq!(row.get("name"), Some(&Value::String("Alice".to_string())));
1407 }
1408
1409 #[test]
1410 fn test_row_data_get_with_prefix() {
1411 let mut row = RowData::empty();
1412 row.set("dept_id", Value::I64(10));
1413 row.set("dept_name", Value::String("Engineering".to_string()));
1414
1415 assert_eq!(row.get_with_prefix("dept_", "id"), Some(&Value::I64(10)));
1416 assert_eq!(
1417 row.get_with_prefix("dept_", "name"),
1418 Some(&Value::String("Engineering".to_string()))
1419 );
1420 assert_eq!(row.get_with_prefix("dept_", "missing"), None);
1421 }
1422
1423 #[test]
1424 fn test_row_data_is_not_null() {
1425 let mut row = RowData::empty();
1426 row.set("a", Value::I64(1));
1427 row.set("b", Value::Null);
1428
1429 assert!(row.is_not_null("a"));
1430 assert!(!row.is_not_null("b"));
1431 assert!(!row.is_not_null("missing"));
1432 }
1433
1434 #[test]
1435 fn test_row_data_column_names() {
1436 let mut row = RowData::empty();
1437 row.set("id", Value::I64(1));
1438 row.set("name", Value::String("Alice".to_string()));
1439
1440 let names = row.column_names();
1441 assert_eq!(names.len(), 2);
1442 assert!(names.contains(&"id".to_string()));
1443 assert!(names.contains(&"name".to_string()));
1444 }
1445
1446 #[test]
1449 fn test_apply_result_map_basic() {
1450 let registry = ResultMapRegistry::new();
1451 let mut rm = ResultMap::new("userMap", "User");
1452 rm.add_id_mapping(Mapping::new("id", "user_id"))
1453 .add_result_mapping(Mapping::new("name", "user_name"));
1454 registry.register(rm);
1455
1456 let mut row = RowData::empty();
1457 row.set("user_id", Value::I64(1));
1458 row.set("user_name", Value::String("Alice".to_string()));
1459
1460 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1461 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1462 assert_eq!(attrs.get("name"), Some(&Value::String("Alice".to_string())));
1463 }
1464
1465 #[test]
1466 fn test_apply_result_map_missing_column() {
1467 let registry = ResultMapRegistry::new();
1468 let mut rm = ResultMap::new("userMap", "User");
1469 rm.add_id_mapping(Mapping::new("id", "user_id"))
1470 .add_result_mapping(Mapping::new("name", "user_name"));
1471 registry.register(rm);
1472
1473 let row = RowData::empty();
1474 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1475 assert!(!attrs.contains_key("id"));
1477 assert!(!attrs.contains_key("name"));
1478 }
1479
1480 #[test]
1481 fn test_apply_result_map_not_found() {
1482 let registry = ResultMapRegistry::new();
1483 let row = RowData::empty();
1484 let err = apply_result_map(®istry, "missingMap", &row).unwrap_err();
1485 match err {
1486 ResultMapError::MapNotFound { id } => assert_eq!(id, "missingMap"),
1487 _ => panic!("expected MapNotFound"),
1488 }
1489 }
1490
1491 #[test]
1494 fn test_apply_result_map_with_association() {
1495 let registry = ResultMapRegistry::new();
1496
1497 let mut dept_map = ResultMap::new("deptMap", "Dept");
1498 dept_map
1499 .add_id_mapping(Mapping::new("id", "dept_id"))
1500 .add_result_mapping(Mapping::new("name", "dept_name"));
1501 registry.register(dept_map);
1502
1503 let mut user_map = ResultMap::new("userMap", "User");
1504 user_map
1505 .add_id_mapping(Mapping::new("id", "user_id"))
1506 .add_result_mapping(Mapping::new("name", "user_name"))
1507 .add_association(NestedAssociation::new("dept", "deptMap"));
1508 registry.register(user_map);
1509
1510 let mut row = RowData::empty();
1511 row.set("user_id", Value::I64(1));
1512 row.set("user_name", Value::String("Alice".to_string()));
1513 row.set("dept_id", Value::I64(10));
1514 row.set("dept_name", Value::String("Engineering".to_string()));
1515
1516 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1517 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1518 let dept = attrs.get("dept");
1519 assert!(dept.is_some());
1520 if let Some(Value::Object(dept_attrs)) = dept {
1521 assert_eq!(dept_attrs.get("id"), Some(&Value::I64(10)));
1522 assert_eq!(
1523 dept_attrs.get("name"),
1524 Some(&Value::String("Engineering".to_string()))
1525 );
1526 }
1527 }
1528
1529 #[test]
1530 fn test_apply_result_map_association_not_null_column_skip() {
1531 let registry = ResultMapRegistry::new();
1532
1533 let mut dept_map = ResultMap::new("deptMap", "Dept");
1534 dept_map
1535 .add_id_mapping(Mapping::new("id", "dept_id"))
1536 .add_result_mapping(Mapping::new("name", "dept_name"));
1537 registry.register(dept_map);
1538
1539 let mut user_map = ResultMap::new("userMap", "User");
1540 user_map
1541 .add_id_mapping(Mapping::new("id", "user_id"))
1542 .add_result_mapping(Mapping::new("name", "user_name"))
1543 .add_association(
1544 NestedAssociation::new("dept", "deptMap").with_not_null_column("dept_id"),
1545 );
1546 registry.register(user_map);
1547
1548 let mut row = RowData::empty();
1550 row.set("user_id", Value::I64(1));
1551 row.set("user_name", Value::String("Alice".to_string()));
1552 row.set("dept_id", Value::Null);
1553
1554 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1555 assert!(!attrs.contains_key("dept"));
1557 }
1558
1559 #[test]
1560 fn test_apply_result_map_association_with_prefix() {
1561 let registry = ResultMapRegistry::new();
1562
1563 let mut dept_map = ResultMap::new("deptMap", "Dept");
1564 dept_map
1565 .add_id_mapping(Mapping::new("id", "id"))
1566 .add_result_mapping(Mapping::new("name", "name"));
1567 registry.register(dept_map);
1568
1569 let mut user_map = ResultMap::new("userMap", "User");
1570 user_map
1571 .add_id_mapping(Mapping::new("id", "id"))
1572 .add_result_mapping(Mapping::new("name", "name"))
1573 .add_association(NestedAssociation::new("dept", "deptMap").with_prefix("d_"));
1574 registry.register(user_map);
1575
1576 let mut row = RowData::empty();
1578 row.set("id", Value::I64(1));
1579 row.set("name", Value::String("Alice".to_string()));
1580 row.set("d_id", Value::I64(10));
1581 row.set("d_name", Value::String("Engineering".to_string()));
1582
1583 let attrs = apply_result_map(®istry, "userMap", &row).unwrap();
1584 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1585 assert_eq!(attrs.get("name"), Some(&Value::String("Alice".to_string())));
1586
1587 if let Some(Value::Object(dept_attrs)) = attrs.get("dept") {
1588 assert_eq!(dept_attrs.get("id"), Some(&Value::I64(10)));
1589 assert_eq!(
1590 dept_attrs.get("name"),
1591 Some(&Value::String("Engineering".to_string()))
1592 );
1593 } else {
1594 panic!("dept should be an Object");
1595 }
1596 }
1597
1598 #[test]
1601 fn test_apply_result_map_discriminator() {
1602 let registry = ResultMapRegistry::new();
1603
1604 let mut admin_map = ResultMap::new("adminMap", "AdminUser");
1606 admin_map
1607 .add_id_mapping(Mapping::new("id", "user_id"))
1608 .add_result_mapping(Mapping::new("name", "user_name"))
1609 .add_result_mapping(Mapping::new("admin_level", "extra_level"));
1610 registry.register(admin_map);
1611
1612 let mut normal_map = ResultMap::new("normalMap", "NormalUser");
1614 normal_map
1615 .add_id_mapping(Mapping::new("id", "user_id"))
1616 .add_result_mapping(Mapping::new("name", "user_name"));
1617 registry.register(normal_map);
1618
1619 let mut base_map = ResultMap::new("baseMap", "User");
1621 base_map
1622 .add_id_mapping(Mapping::new("id", "user_id"))
1623 .add_result_mapping(Mapping::new("name", "user_name"))
1624 .set_discriminator({
1625 let mut d = Discriminator::new("user_type");
1626 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1627 d.add_case(DiscriminatorCase::new(Value::I64(2), "normalMap"));
1628 d
1629 });
1630 registry.register(base_map);
1631
1632 let mut row = RowData::empty();
1634 row.set("user_id", Value::I64(1));
1635 row.set("user_name", Value::String("Alice".to_string()));
1636 row.set("user_type", Value::I64(1));
1637 row.set("extra_level", Value::I64(5));
1638
1639 let attrs = apply_result_map(®istry, "baseMap", &row).unwrap();
1640 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1641 assert_eq!(attrs.get("admin_level"), Some(&Value::I64(5)));
1642
1643 let mut row2 = RowData::empty();
1645 row2.set("user_id", Value::I64(2));
1646 row2.set("user_name", Value::String("Bob".to_string()));
1647 row2.set("user_type", Value::I64(2));
1648
1649 let attrs2 = apply_result_map(®istry, "baseMap", &row2).unwrap();
1650 assert_eq!(attrs2.get("id"), Some(&Value::I64(2)));
1651 assert!(!attrs2.contains_key("admin_level")); }
1653
1654 #[test]
1655 fn test_apply_result_map_discriminator_no_match_falls_back_to_base() {
1656 let registry = ResultMapRegistry::new();
1657
1658 let mut base_map = ResultMap::new("baseMap", "User");
1659 base_map
1660 .add_id_mapping(Mapping::new("id", "user_id"))
1661 .set_discriminator({
1662 let mut d = Discriminator::new("user_type");
1663 d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1664 d
1665 });
1666 registry.register(base_map);
1667
1668 let mut row = RowData::empty();
1670 row.set("user_id", Value::I64(1));
1671 row.set("user_type", Value::I64(99));
1672
1673 let attrs = apply_result_map(®istry, "baseMap", &row).unwrap();
1674 assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1675 }
1676
1677 #[test]
1680 fn test_apply_result_map_many_collection_aggregation() {
1681 let registry = ResultMapRegistry::new();
1682
1683 let mut role_map = ResultMap::new("roleMap", "Role");
1684 role_map
1685 .add_id_mapping(Mapping::new("id", "role_id"))
1686 .add_result_mapping(Mapping::new("name", "role_name"));
1687 registry.register(role_map);
1688
1689 let mut user_map = ResultMap::new("userMap", "User");
1690 user_map
1691 .add_id_mapping(Mapping::new("id", "user_id"))
1692 .add_result_mapping(Mapping::new("name", "user_name"))
1693 .add_collection(NestedCollection::new("roles", "roleMap"));
1694 registry.register(user_map);
1695
1696 let rows = vec![
1698 {
1699 let mut r = RowData::empty();
1700 r.set("user_id", Value::I64(1));
1701 r.set("user_name", Value::String("Alice".to_string()));
1702 r.set("role_id", Value::I64(100));
1703 r.set("role_name", Value::String("admin".to_string()));
1704 r
1705 },
1706 {
1707 let mut r = RowData::empty();
1708 r.set("user_id", Value::I64(1));
1709 r.set("user_name", Value::String("Alice".to_string()));
1710 r.set("role_id", Value::I64(101));
1711 r.set("role_name", Value::String("editor".to_string()));
1712 r
1713 },
1714 ];
1715
1716 let result = apply_result_map_many(®istry, "userMap", &rows).unwrap();
1717 assert_eq!(result.len(), 1); let user = &result[0];
1719 assert_eq!(user.get("id"), Some(&Value::I64(1)));
1720 let roles = user.get("roles");
1721 assert!(roles.is_some());
1722 if let Some(Value::Array(items)) = roles {
1723 assert_eq!(items.len(), 2);
1724 }
1725 }
1726
1727 #[test]
1728 fn test_apply_result_map_many_multi_users() {
1729 let registry = ResultMapRegistry::new();
1730
1731 let mut role_map = ResultMap::new("roleMap", "Role");
1732 role_map
1733 .add_id_mapping(Mapping::new("id", "role_id"))
1734 .add_result_mapping(Mapping::new("name", "role_name"));
1735 registry.register(role_map);
1736
1737 let mut user_map = ResultMap::new("userMap", "User");
1738 user_map
1739 .add_id_mapping(Mapping::new("id", "user_id"))
1740 .add_result_mapping(Mapping::new("name", "user_name"))
1741 .add_collection(NestedCollection::new("roles", "roleMap"));
1742 registry.register(user_map);
1743
1744 let rows = vec![
1745 {
1746 let mut r = RowData::empty();
1747 r.set("user_id", Value::I64(1));
1748 r.set("user_name", Value::String("Alice".to_string()));
1749 r.set("role_id", Value::I64(100));
1750 r.set("role_name", Value::String("admin".to_string()));
1751 r
1752 },
1753 {
1754 let mut r = RowData::empty();
1755 r.set("user_id", Value::I64(2));
1756 r.set("user_name", Value::String("Bob".to_string()));
1757 r.set("role_id", Value::I64(101));
1758 r.set("role_name", Value::String("editor".to_string()));
1759 r
1760 },
1761 ];
1762
1763 let result = apply_result_map_many(®istry, "userMap", &rows).unwrap();
1764 assert_eq!(result.len(), 2);
1765 assert_eq!(result[0].get("id"), Some(&Value::I64(1)));
1767 assert_eq!(result[1].get("id"), Some(&Value::I64(2)));
1768 }
1769
1770 #[test]
1771 fn test_apply_result_map_many_empty() {
1772 let registry = ResultMapRegistry::new();
1773 registry.register(ResultMap::new("userMap", "User"));
1774
1775 let result = apply_result_map_many(®istry, "userMap", &[]).unwrap();
1776 assert!(result.is_empty());
1777 }
1778
1779 #[test]
1782 fn test_entity_result_new() {
1783 let er = EntityResult::new("User");
1784 assert_eq!(er.entity_class, "User");
1785 assert!(er.fields.is_empty());
1786 assert_eq!(er.discriminator_column, None);
1787 }
1788
1789 #[test]
1790 fn test_entity_result_add_field() {
1791 let mut er = EntityResult::new("User");
1792 er.add_field(FieldResult::new("id", "user_id"))
1793 .add_field(FieldResult::new("name", "user_name"));
1794 assert_eq!(er.fields.len(), 2);
1795 }
1796
1797 #[test]
1798 fn test_entity_result_with_discriminator() {
1799 let er = EntityResult::new("User").with_discriminator_column("user_type");
1800 assert_eq!(er.discriminator_column.as_deref(), Some("user_type"));
1801 }
1802
1803 #[test]
1804 fn test_scalar_result_new() {
1805 let s = ScalarResult::new("count", "i64");
1806 assert_eq!(s.column, "count");
1807 assert_eq!(s.type_name, "i64");
1808 }
1809
1810 #[test]
1811 fn test_result_set_mapping_new() {
1812 let rsm = ResultSetMapping::new("userCount");
1813 assert_eq!(rsm.name, "userCount");
1814 assert!(rsm.entities.is_empty());
1815 assert!(rsm.scalars.is_empty());
1816 }
1817
1818 #[test]
1819 fn test_result_set_mapping_add() {
1820 let mut rsm = ResultSetMapping::new("userWithCount");
1821 rsm.add_entity(EntityResult::new("User"))
1822 .add_scalar(ScalarResult::new("total", "i64"));
1823 assert_eq!(rsm.entities.len(), 1);
1824 assert_eq!(rsm.scalars.len(), 1);
1825 }
1826
1827 #[test]
1830 fn test_rsm_registry() {
1831 let reg = ResultSetMappingRegistry::new();
1832 reg.register(ResultSetMapping::new("mapping1"));
1833 assert!(reg.contains("mapping1"));
1834 assert!(!reg.contains("missing"));
1835 assert_eq!(reg.len(), 1);
1836 assert!(reg.get("mapping1").is_some());
1837 assert!(reg.get("missing").is_none());
1838 }
1839
1840 #[test]
1843 fn test_native_query_new() {
1844 let nq = NativeQuery::new("SELECT * FROM users WHERE id = ?", "userMapping");
1845 assert_eq!(nq.sql, "SELECT * FROM users WHERE id = ?");
1846 assert_eq!(nq.result_set_mapping, "userMapping");
1847 assert!(nq.parameters.is_empty());
1848 }
1849
1850 #[test]
1851 fn test_native_query_bind() {
1852 let mut nq = NativeQuery::new("SELECT * FROM users WHERE id = ?", "userMapping");
1853 nq.bind(Value::I64(1));
1854 assert_eq!(nq.parameters.len(), 1);
1855 assert_eq!(nq.parameters[0], Value::I64(1));
1856 }
1857
1858 #[test]
1859 fn test_native_query_bind_many() {
1860 let mut nq = NativeQuery::new("SELECT * FROM users WHERE id IN (?, ?)", "userMapping");
1861 nq.bind_many(vec![Value::I64(1), Value::I64(2)]);
1862 assert_eq!(nq.parameters.len(), 2);
1863 }
1864
1865 #[test]
1868 fn test_apply_result_set_mapping_entities_only() {
1869 let mut rsm = ResultSetMapping::new("userMapping");
1870 let mut er = EntityResult::new("User");
1871 er.add_field(FieldResult::new("id", "user_id"))
1872 .add_field(FieldResult::new("name", "user_name"));
1873 rsm.add_entity(er);
1874
1875 let mut row = RowData::empty();
1876 row.set("user_id", Value::I64(1));
1877 row.set("user_name", Value::String("Alice".to_string()));
1878
1879 let (entities, scalars) = apply_result_set_mapping(&rsm, &row);
1880 assert_eq!(entities.len(), 1);
1881 assert_eq!(entities[0].get("id"), Some(&Value::I64(1)));
1882 assert_eq!(
1883 entities[0].get("name"),
1884 Some(&Value::String("Alice".to_string()))
1885 );
1886 assert!(scalars.is_empty());
1887 }
1888
1889 #[test]
1890 fn test_apply_result_set_mapping_scalars_only() {
1891 let mut rsm = ResultSetMapping::new("countMapping");
1892 rsm.add_scalar(ScalarResult::new("total", "i64"))
1893 .add_scalar(ScalarResult::new("avg_age", "f64"));
1894
1895 let mut row = RowData::empty();
1896 row.set("total", Value::I64(100));
1897 row.set("avg_age", Value::F64(25.5));
1898
1899 let (entities, scalars) = apply_result_set_mapping(&rsm, &row);
1900 assert!(entities.is_empty());
1901 assert_eq!(scalars.len(), 2);
1902 assert_eq!(scalars[0], Value::I64(100));
1903 assert_eq!(scalars[1], Value::F64(25.5));
1904 }
1905
1906 #[test]
1907 fn test_apply_result_set_mapping_mixed() {
1908 let mut rsm = ResultSetMapping::new("userWithCount");
1909 let mut er = EntityResult::new("User");
1910 er.add_field(FieldResult::new("id", "user_id"))
1911 .add_field(FieldResult::new("name", "user_name"));
1912 rsm.add_entity(er);
1913 rsm.add_scalar(ScalarResult::new("total_orders", "i64"));
1914
1915 let mut row = RowData::empty();
1916 row.set("user_id", Value::I64(1));
1917 row.set("user_name", Value::String("Alice".to_string()));
1918 row.set("total_orders", Value::I64(42));
1919
1920 let (entities, scalars) = apply_result_set_mapping(&rsm, &row);
1921 assert_eq!(entities.len(), 1);
1922 assert_eq!(scalars.len(), 1);
1923 assert_eq!(entities[0].get("id"), Some(&Value::I64(1)));
1924 assert_eq!(scalars[0], Value::I64(42));
1925 }
1926
1927 #[test]
1928 fn test_apply_result_set_mapping_many() {
1929 let mut rsm = ResultSetMapping::new("userMapping");
1930 let mut er = EntityResult::new("User");
1931 er.add_field(FieldResult::new("id", "user_id"));
1932 rsm.add_entity(er);
1933
1934 let rows = vec![
1935 {
1936 let mut r = RowData::empty();
1937 r.set("user_id", Value::I64(1));
1938 r
1939 },
1940 {
1941 let mut r = RowData::empty();
1942 r.set("user_id", Value::I64(2));
1943 r
1944 },
1945 ];
1946
1947 let results = apply_result_set_mapping_many(&rsm, &rows);
1948 assert_eq!(results.len(), 2);
1949 assert_eq!(results[0].0[0].get("id"), Some(&Value::I64(1)));
1950 assert_eq!(results[1].0[0].get("id"), Some(&Value::I64(2)));
1951 }
1952
1953 #[test]
1956 fn test_e2e_user_with_dept_and_roles() {
1957 let registry = ResultMapRegistry::new();
1958
1959 let mut role_map = ResultMap::new("roleMap", "Role");
1961 role_map
1962 .add_id_mapping(Mapping::new("id", "role_id"))
1963 .add_result_mapping(Mapping::new("name", "role_name"));
1964 registry.register(role_map);
1965
1966 let mut dept_map = ResultMap::new("deptMap", "Dept");
1968 dept_map
1969 .add_id_mapping(Mapping::new("id", "dept_id"))
1970 .add_result_mapping(Mapping::new("name", "dept_name"));
1971 registry.register(dept_map);
1972
1973 let mut user_map = ResultMap::new("userMap", "User");
1975 user_map
1976 .add_id_mapping(Mapping::new("id", "user_id"))
1977 .add_result_mapping(Mapping::new("name", "user_name"))
1978 .add_association(NestedAssociation::new("dept", "deptMap"))
1979 .add_collection(NestedCollection::new("roles", "roleMap"));
1980 registry.register(user_map);
1981
1982 let rows = vec![
1984 {
1985 let mut r = RowData::empty();
1986 r.set("user_id", Value::I64(1));
1987 r.set("user_name", Value::String("Alice".to_string()));
1988 r.set("dept_id", Value::I64(10));
1989 r.set("dept_name", Value::String("Engineering".to_string()));
1990 r.set("role_id", Value::I64(100));
1991 r.set("role_name", Value::String("admin".to_string()));
1992 r
1993 },
1994 {
1995 let mut r = RowData::empty();
1996 r.set("user_id", Value::I64(1));
1997 r.set("user_name", Value::String("Alice".to_string()));
1998 r.set("dept_id", Value::I64(10));
1999 r.set("dept_name", Value::String("Engineering".to_string()));
2000 r.set("role_id", Value::I64(101));
2001 r.set("role_name", Value::String("editor".to_string()));
2002 r
2003 },
2004 ];
2005
2006 let result = apply_result_map_many(®istry, "userMap", &rows).unwrap();
2007 assert_eq!(result.len(), 1);
2008 let user = &result[0];
2009 assert_eq!(user.get("id"), Some(&Value::I64(1)));
2010 assert_eq!(user.get("name"), Some(&Value::String("Alice".to_string())));
2011
2012 if let Some(Value::Object(dept_attrs)) = user.get("dept") {
2014 assert_eq!(dept_attrs.get("id"), Some(&Value::I64(10)));
2015 assert_eq!(
2016 dept_attrs.get("name"),
2017 Some(&Value::String("Engineering".to_string()))
2018 );
2019 } else {
2020 panic!("dept should be an Object");
2021 }
2022
2023 if let Some(Value::Array(roles)) = user.get("roles") {
2025 assert_eq!(roles.len(), 2);
2026 } else {
2027 panic!("roles should be an Array");
2028 }
2029 }
2030
2031 #[test]
2032 fn test_e2e_native_query_with_rsm() {
2033 let mut rsm = ResultSetMapping::new("userOrderCount");
2037 let mut er = EntityResult::new("User");
2038 er.add_field(FieldResult::new("id", "user_id"))
2039 .add_field(FieldResult::new("name", "user_name"));
2040 rsm.add_entity(er);
2041 rsm.add_scalar(ScalarResult::new("order_count", "i64"));
2042
2043 let mut nq = NativeQuery::new(
2044 "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",
2045 "userOrderCount",
2046 );
2047 nq.bind(Value::Null); let rows = vec![
2051 {
2052 let mut r = RowData::empty();
2053 r.set("user_id", Value::I64(1));
2054 r.set("user_name", Value::String("Alice".to_string()));
2055 r.set("order_count", Value::I64(5));
2056 r
2057 },
2058 {
2059 let mut r = RowData::empty();
2060 r.set("user_id", Value::I64(2));
2061 r.set("user_name", Value::String("Bob".to_string()));
2062 r.set("order_count", Value::I64(3));
2063 r
2064 },
2065 ];
2066
2067 let reg = ResultSetMappingRegistry::new();
2068 reg.register(rsm.clone());
2069 assert!(reg.contains("userOrderCount"));
2070
2071 let results = apply_result_set_mapping_many(&rsm, &rows);
2072 assert_eq!(results.len(), 2);
2073 assert_eq!(results[0].0[0].get("id"), Some(&Value::I64(1)));
2074 assert_eq!(results[0].1[0], Value::I64(5));
2075 assert_eq!(results[1].0[0].get("id"), Some(&Value::I64(2)));
2076 assert_eq!(results[1].1[0], Value::I64(3));
2077
2078 assert_eq!(nq.result_set_mapping, "userOrderCount");
2080 assert_eq!(nq.parameters.len(), 1);
2081 }
2082
2083 #[cfg(feature = "zero-copy")]
2086 #[test]
2087 fn test_apply_result_map_borrowed_basic_equivalence() {
2088 use crate::value_borrowed::{BorrowedRowData, BorrowedValue};
2089
2090 let registry = ResultMapRegistry::new();
2091 let mut rm = ResultMap::new("userMap", "User");
2092 rm.add_id_mapping(Mapping::new("id", "user_id"))
2093 .add_result_mapping(Mapping::new("name", "user_name"));
2094 registry.register(rm);
2095
2096 let mut row = RowData::empty();
2097 row.set("user_id", Value::I64(42));
2098 row.set("user_name", Value::String("Alice".into()));
2099
2100 let v_id = Value::I64(42);
2101 let v_name = Value::String("Alice".into());
2102 let mut borrowed_row = BorrowedRowData::new();
2103 borrowed_row.set("user_id", BorrowedValue::from_value(&v_id));
2104 borrowed_row.set("user_name", BorrowedValue::from_value(&v_name));
2105
2106 let owned_result = apply_result_map(®istry, "userMap", &row).unwrap();
2107 let borrowed_result =
2108 apply_result_map_borrowed(®istry, "userMap", &borrowed_row).unwrap();
2109
2110 assert_eq!(owned_result.len(), borrowed_result.len());
2111 assert_eq!(owned_result.get("id"), Some(&Value::I64(42)));
2112 assert_eq!(
2113 borrowed_result.get("id").map(|v| v.to_owned_value()),
2114 Some(Value::I64(42))
2115 );
2116 assert_eq!(
2117 owned_result.get("name"),
2118 Some(&Value::String("Alice".into()))
2119 );
2120 assert_eq!(
2121 borrowed_result.get("name").map(|v| v.to_owned_value()),
2122 Some(Value::String("Alice".into()))
2123 );
2124 }
2125
2126 #[cfg(feature = "zero-copy")]
2127 #[test]
2128 fn test_apply_result_map_borrowed_association_equivalence() {
2129 use crate::value_borrowed::{BorrowedRowData, BorrowedValue};
2130
2131 let registry = ResultMapRegistry::new();
2132
2133 let mut dept_map = ResultMap::new("deptMap", "Dept");
2134 dept_map
2135 .add_id_mapping(Mapping::new("id", "id"))
2136 .add_result_mapping(Mapping::new("name", "name"));
2137 registry.register(dept_map);
2138
2139 let mut user_map = ResultMap::new("userMap", "User");
2140 user_map
2141 .add_id_mapping(Mapping::new("id", "user_id"))
2142 .add_result_mapping(Mapping::new("name", "user_name"))
2143 .add_association(NestedAssociation::new("dept", "deptMap").with_prefix("dept_"));
2144 registry.register(user_map);
2145
2146 let mut row = RowData::empty();
2147 row.set("user_id", Value::I64(1));
2148 row.set("user_name", Value::String("Alice".into()));
2149 row.set("dept_id", Value::I64(10));
2150 row.set("dept_name", Value::String("Engineering".into()));
2151
2152 let mut borrowed_row = BorrowedRowData::new();
2153 for (k, v) in &row.columns {
2154 borrowed_row.set(k.clone(), BorrowedValue::from_value(v));
2155 }
2156
2157 let owned_result = apply_result_map(®istry, "userMap", &row).unwrap();
2158 let borrowed_result =
2159 apply_result_map_borrowed(®istry, "userMap", &borrowed_row).unwrap();
2160
2161 assert_eq!(owned_result.get("id"), Some(&Value::I64(1)));
2162 assert_eq!(
2163 borrowed_result.get("id").map(|v| v.to_owned_value()),
2164 Some(Value::I64(1))
2165 );
2166
2167 let owned_dept = owned_result.get("dept").and_then(|v| match v {
2168 Value::Object(m) => Some(m),
2169 _ => None,
2170 });
2171 let borrowed_dept = borrowed_result.get("dept").and_then(|v| match v {
2172 BorrowedValue::Object(m) => Some(m),
2173 _ => None,
2174 });
2175 assert!(owned_dept.is_some() && borrowed_dept.is_some());
2176 let owned_dept = owned_dept.unwrap();
2177 let borrowed_dept = borrowed_dept.unwrap();
2178 assert_eq!(owned_dept.get("id"), Some(&Value::I64(10)));
2179 assert_eq!(
2180 borrowed_dept.get("id").map(|v| v.to_owned_value()),
2181 Some(Value::I64(10))
2182 );
2183 }
2184
2185 #[cfg(feature = "zero-copy")]
2186 #[test]
2187 fn test_apply_result_map_borrowed_many_equivalence() {
2188 use crate::value_borrowed::{BorrowedRowData, BorrowedValue};
2189
2190 let registry = ResultMapRegistry::new();
2191
2192 let mut order_map = ResultMap::new("orderMap", "Order");
2193 order_map
2194 .add_id_mapping(Mapping::new("id", "order_id"))
2195 .add_result_mapping(Mapping::new("amount", "order_amount"));
2196 registry.register(order_map);
2197
2198 let mut user_map = ResultMap::new("userMap", "User");
2199 user_map
2200 .add_id_mapping(Mapping::new("id", "user_id"))
2201 .add_result_mapping(Mapping::new("name", "user_name"))
2202 .add_collection(NestedCollection::new("orders", "orderMap"));
2203 registry.register(user_map);
2204
2205 let rows: Vec<RowData> = vec![
2206 {
2207 let mut r = RowData::empty();
2208 r.set("user_id", Value::I64(1));
2209 r.set("user_name", Value::String("Alice".into()));
2210 r.set("order_id", Value::I64(100));
2211 r.set("order_amount", Value::F64(50.0));
2212 r
2213 },
2214 {
2215 let mut r = RowData::empty();
2216 r.set("user_id", Value::I64(1));
2217 r.set("user_name", Value::String("Alice".into()));
2218 r.set("order_id", Value::I64(101));
2219 r.set("order_amount", Value::F64(75.0));
2220 r
2221 },
2222 ];
2223
2224 let borrowed_rows: Vec<BorrowedRowData> = rows
2225 .iter()
2226 .map(|r| {
2227 let mut br = BorrowedRowData::new();
2228 for (k, v) in &r.columns {
2229 br.set(k.clone(), BorrowedValue::from_value(v));
2230 }
2231 br
2232 })
2233 .collect();
2234
2235 let owned_result = apply_result_map_many(®istry, "userMap", &rows).unwrap();
2236 let borrowed_result =
2237 apply_result_map_many_borrowed(®istry, "userMap", &borrowed_rows).unwrap();
2238
2239 assert_eq!(owned_result.len(), borrowed_result.len());
2240 assert_eq!(owned_result.len(), 1);
2241
2242 let owned_orders = owned_result[0].get("orders").and_then(|v| match v {
2243 Value::Array(a) => Some(a),
2244 _ => None,
2245 });
2246 let borrowed_orders = borrowed_result[0].get("orders").and_then(|v| match v {
2247 BorrowedValue::Array(a) => Some(a),
2248 _ => None,
2249 });
2250 assert!(owned_orders.is_some() && borrowed_orders.is_some());
2251 assert_eq!(owned_orders.unwrap().len(), 2);
2252 assert_eq!(borrowed_orders.unwrap().len(), 2);
2253 }
2254
2255 #[cfg(feature = "zero-copy")]
2256 #[test]
2257 fn test_apply_result_map_borrowed_discriminator_equivalence() {
2258 use crate::value_borrowed::{BorrowedRowData, BorrowedValue};
2259
2260 let registry = ResultMapRegistry::new();
2261
2262 let mut admin_map = ResultMap::new("adminMap", "Admin");
2263 admin_map
2264 .add_id_mapping(Mapping::new("id", "id"))
2265 .add_result_mapping(Mapping::new("level", "admin_level"));
2266 registry.register(admin_map);
2267
2268 let mut user_map = ResultMap::new("userMap", "User");
2269 user_map
2270 .add_id_mapping(Mapping::new("id", "id"))
2271 .add_result_mapping(Mapping::new("name", "user_name"));
2272 registry.register(user_map);
2273
2274 let mut base_map = ResultMap::new("personMap", "Person");
2275 base_map
2276 .add_id_mapping(Mapping::new("id", "id"))
2277 .set_discriminator({
2278 let mut disc = Discriminator::new("type");
2279 disc.add_case(DiscriminatorCase::new(
2280 Value::String("admin".into()),
2281 "adminMap",
2282 ));
2283 disc.add_case(DiscriminatorCase::new(
2284 Value::String("user".into()),
2285 "userMap",
2286 ));
2287 disc
2288 });
2289 registry.register(base_map);
2290
2291 let mut row = RowData::empty();
2292 row.set("id", Value::I64(1));
2293 row.set("type", Value::String("admin".into()));
2294 row.set("admin_level", Value::I64(5));
2295
2296 let mut borrowed_row = BorrowedRowData::new();
2297 for (k, v) in &row.columns {
2298 borrowed_row.set(k.clone(), BorrowedValue::from_value(v));
2299 }
2300
2301 let owned_result = apply_result_map(®istry, "personMap", &row).unwrap();
2302 let borrowed_result =
2303 apply_result_map_borrowed(®istry, "personMap", &borrowed_row).unwrap();
2304
2305 assert_eq!(owned_result.get("level"), Some(&Value::I64(5)));
2306 assert_eq!(
2307 borrowed_result.get("level").map(|v| v.to_owned_value()),
2308 Some(Value::I64(5))
2309 );
2310 }
2311}