Skip to main content

sz_orm_core/
result_map.rs

1//! ResultMap 高级映射 + Native Query + ResultSetMapping
2//!
3//! 对应文档 6.8 节改进项 30(ResultMap 高级映射)+ 42(Native Query + ResultSetMapping)。
4//!
5//! # 核心概念
6//!
7//! - **ResultMap**:声明式结果映射规则(id property + result property + association + collection + discriminator)
8//! - **ResultSetMapping**:Hibernate `@SqlResultSetMapping` 风格,原生 SQL 的结果映射
9//! - **NativeQuery**:原生 SQL + ResultSetMapping 引用
10//! - **ResultMapRegistry**:注册中心,按 id 索引
11//! - **RowData**:行数据(列名 -> Value)
12//!
13//! # 设计灵感
14//!
15//! - MyBatis `resultMap`(最强大的 resultMap 模型,支持 discriminator 多态、association/collection 嵌套)
16//! - Hibernate `@SqlResultSetMapping`(JPA 标准)
17//! - Doctrine `ResultSetMappingBuilder`
18//!
19//! # 优势
20//!
21//! 1. **多态鉴别器**:通过 discriminator 按列值分派到不同 ResultMap
22//! 2. **嵌套映射**:association(一对一)+ collection(一对多)支持嵌套
23//! 3. **列前缀**:JOIN 查询结果通过列前缀隔离不同实体的列
24//! 4. **原生 SQL**:NativeQuery 可执行任意 SQL 并通过 ResultSetMapping 映射
25//!
26//! # 使用示例
27//!
28//! ```
29//! use sz_orm_core::result_map::{
30//!     ResultMap, Mapping, NestedAssociation, ResultMapRegistry, RowData, apply_result_map,
31//! };
32//! use sz_orm_core::Value;
33//! use std::collections::HashMap;
34//!
35//! // 1. 注册 ResultMap
36//! let mut registry = ResultMapRegistry::new();
37//!
38//! let mut dept_map = ResultMap::new("deptMap", "Dept");
39//! dept_map.add_id_mapping(Mapping::new("id", "dept_id"));
40//! dept_map.add_result_mapping(Mapping::new("name", "dept_name"));
41//! registry.register(dept_map);
42//!
43//! let mut user_map = ResultMap::new("userMap", "User");
44//! user_map.add_id_mapping(Mapping::new("id", "user_id"));
45//! user_map.add_result_mapping(Mapping::new("name", "user_name"));
46//! user_map.add_association(NestedAssociation::new("dept", "deptMap"));
47//! registry.register(user_map);
48//!
49//! // 2. 构造 JOIN 查询结果行
50//! let mut columns = HashMap::new();
51//! columns.insert("user_id".to_string(), Value::I64(1));
52//! columns.insert("user_name".to_string(), Value::String("Alice".to_string()));
53//! columns.insert("dept_id".to_string(), Value::I64(10));
54//! columns.insert("dept_name".to_string(), Value::String("Engineering".to_string()));
55//! let row = RowData::new(columns);
56//!
57//! // 3. 应用 ResultMap 映射
58//! let result = apply_result_map(&registry, "userMap", &row).unwrap();
59//! assert_eq!(result.get("id"), Some(&Value::I64(1)));
60//! assert_eq!(result.get("name"), Some(&Value::String("Alice".to_string())));
61//! ```
62
63use crate::Value;
64use parking_lot::RwLock;
65use std::collections::HashMap;
66
67// ============================================================================
68// Mapping — 单字段映射规则
69// ============================================================================
70
71/// 单字段映射规则(property <-> column)
72#[derive(Debug, Clone, PartialEq, Eq)]
73pub struct Mapping {
74    /// 目标属性名(Rust 字段名)
75    pub property: String,
76    /// 数据库列名
77    pub column: String,
78    /// 可选 TypeHandler 名称(用于自定义类型转换)
79    pub type_handler: Option<String>,
80}
81
82impl Mapping {
83    /// 创建字段映射
84    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    /// 创建带 TypeHandler 的字段映射
93    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// ============================================================================
107// NestedAssociation — 一对一嵌套映射
108// ============================================================================
109
110/// 一对一嵌套映射(association)
111#[derive(Debug, Clone, PartialEq, Eq)]
112pub struct NestedAssociation {
113    /// 目标属性名
114    pub property: String,
115    /// 引用的 ResultMap id
116    pub result_map: String,
117    /// 列前缀(用于 JOIN 场景隔离不同实体列)
118    pub column_prefix: Option<String>,
119    /// notNullColumn:仅当该列非 NULL 时才填充(避免 LEFT JOIN NULL 行被填充)
120    pub not_null_column: Option<String>,
121}
122
123impl NestedAssociation {
124    /// 创建嵌套 association
125    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    /// 设置列前缀
135    pub fn with_prefix(mut self, prefix: impl Into<String>) -> Self {
136        self.column_prefix = Some(prefix.into());
137        self
138    }
139
140    /// 设置 notNullColumn
141    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// ============================================================================
148// NestedCollection — 一对多嵌套映射
149// ============================================================================
150
151/// 一对多嵌套映射(collection)
152#[derive(Debug, Clone, PartialEq, Eq)]
153pub struct NestedCollection {
154    /// 目标属性名
155    pub property: String,
156    /// 引用的 ResultMap id
157    pub result_map: String,
158    /// 列前缀
159    pub column_prefix: Option<String>,
160    /// notNullColumn
161    pub not_null_column: Option<String>,
162}
163
164impl NestedCollection {
165    /// 创建嵌套 collection
166    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    /// 设置列前缀
176    pub fn with_prefix(mut self, prefix: impl Into<String>) -> Self {
177        self.column_prefix = Some(prefix.into());
178        self
179    }
180
181    /// 设置 notNullColumn
182    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// ============================================================================
189// Discriminator — 多态鉴别器
190// ============================================================================
191
192/// 多态鉴别器 case
193#[derive(Debug, Clone, PartialEq)]
194pub struct DiscriminatorCase {
195    /// 触发值
196    pub value: Value,
197    /// 该 case 使用的 ResultMap id
198    pub result_map: String,
199}
200
201impl DiscriminatorCase {
202    /// 创建 case
203    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/// 多态鉴别器
212#[derive(Debug, Clone, PartialEq)]
213pub struct Discriminator {
214    /// 鉴别列
215    pub column: String,
216    /// case 列表
217    pub cases: Vec<DiscriminatorCase>,
218}
219
220impl Discriminator {
221    /// 创建鉴别器
222    pub fn new(column: impl Into<String>) -> Self {
223        Self {
224            column: column.into(),
225            cases: Vec::new(),
226        }
227    }
228
229    /// 添加 case
230    pub fn add_case(&mut self, case: DiscriminatorCase) -> &mut Self {
231        self.cases.push(case);
232        self
233    }
234
235    /// 根据值查找对应 ResultMap id
236    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// ============================================================================
247// ResultMap — 完整结果映射规则
248// ============================================================================
249
250/// 完整结果映射规则
251#[derive(Debug, Clone, PartialEq)]
252pub struct ResultMap {
253    /// 唯一 id
254    pub id: String,
255    /// 目标类型名(如 "User")
256    pub type_name: String,
257    /// 主键字段映射(用于唯一性判断、collection 聚合)
258    pub id_mappings: Vec<Mapping>,
259    /// 普通字段映射
260    pub result_mappings: Vec<Mapping>,
261    /// 一对一嵌套映射
262    pub associations: Vec<NestedAssociation>,
263    /// 一对多嵌套映射
264    pub collections: Vec<NestedCollection>,
265    /// 多态鉴别器
266    pub discriminator: Option<Discriminator>,
267}
268
269impl ResultMap {
270    /// 创建 ResultMap
271    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    /// 添加主键映射
284    pub fn add_id_mapping(&mut self, mapping: Mapping) -> &mut Self {
285        self.id_mappings.push(mapping);
286        self
287    }
288
289    /// 添加普通字段映射
290    pub fn add_result_mapping(&mut self, mapping: Mapping) -> &mut Self {
291        self.result_mappings.push(mapping);
292        self
293    }
294
295    /// 添加 association 嵌套
296    pub fn add_association(&mut self, assoc: NestedAssociation) -> &mut Self {
297        self.associations.push(assoc);
298        self
299    }
300
301    /// 添加 collection 嵌套
302    pub fn add_collection(&mut self, coll: NestedCollection) -> &mut Self {
303        self.collections.push(coll);
304        self
305    }
306
307    /// 设置 discriminator
308    pub fn set_discriminator(&mut self, disc: Discriminator) -> &mut Self {
309        self.discriminator = Some(disc);
310        self
311    }
312
313    /// 收集本 ResultMap 直接引用的所有 sub-ResultMap id
314    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// ============================================================================
332// ResultMapRegistry — 注册中心
333// ============================================================================
334
335/// ResultMap 注册中心(线程安全)
336#[derive(Debug, Default)]
337pub struct ResultMapRegistry {
338    maps: RwLock<HashMap<String, ResultMap>>,
339}
340
341impl ResultMapRegistry {
342    /// 创建空注册中心
343    pub fn new() -> Self {
344        Self {
345            maps: RwLock::new(HashMap::new()),
346        }
347    }
348
349    /// 注册 ResultMap(同名覆盖)
350    pub fn register(&self, map: ResultMap) {
351        let mut maps = self.maps.write();
352        maps.insert(map.id.clone(), map);
353    }
354
355    /// 按 id 查找 ResultMap
356    pub fn get(&self, id: &str) -> Option<ResultMap> {
357        let maps = self.maps.read();
358        maps.get(id).cloned()
359    }
360
361    /// 是否包含指定 id
362    pub fn contains(&self, id: &str) -> bool {
363        let maps = self.maps.read();
364        maps.contains_key(id)
365    }
366
367    /// 已注册的 ResultMap 数量
368    pub fn len(&self) -> usize {
369        let maps = self.maps.read();
370        maps.len()
371    }
372
373    /// 是否为空
374    pub fn is_empty(&self) -> bool {
375        self.len() == 0
376    }
377
378    /// 列出所有已注册的 id
379    pub fn list_ids(&self) -> Vec<String> {
380        let maps = self.maps.read();
381        maps.keys().cloned().collect()
382    }
383
384    /// 清空注册中心
385    pub fn clear(&self) {
386        let mut maps = self.maps.write();
387        maps.clear();
388    }
389}
390
391// ============================================================================
392// RowData — 行数据
393// ============================================================================
394
395/// 行数据(列名 -> Value)
396#[derive(Debug, Clone, Default)]
397pub struct RowData {
398    columns: HashMap<String, Value>,
399}
400
401impl RowData {
402    /// 创建空行
403    pub fn new(columns: HashMap<String, Value>) -> Self {
404        Self { columns }
405    }
406
407    /// 创建空行
408    pub fn empty() -> Self {
409        Self {
410            columns: HashMap::new(),
411        }
412    }
413
414    /// 插入/更新列
415    pub fn set(&mut self, column: impl Into<String>, value: Value) {
416        self.columns.insert(column.into(), value);
417    }
418
419    /// 按列名取值
420    pub fn get(&self, column: &str) -> Option<&Value> {
421        self.columns.get(column)
422    }
423
424    /// 按前缀 + 列名取值(用于 JOIN 列前缀隔离)
425    ///
426    /// 例如:prefix="dept_", column="id" 将查找 "dept_id"
427    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    /// 判断列是否存在且非 NULL
433    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    /// 列数
441    pub fn len(&self) -> usize {
442        self.columns.len()
443    }
444
445    /// 是否为空
446    pub fn is_empty(&self) -> bool {
447        self.columns.is_empty()
448    }
449
450    /// 所有列名
451    pub fn column_names(&self) -> Vec<String> {
452        self.columns.keys().cloned().collect()
453    }
454
455    /// 获取所有列的引用(按列名排序)
456    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    /// 获取所有列的迭代器
463    pub fn iter(&self) -> impl Iterator<Item = (&String, &Value)> {
464        self.columns.iter()
465    }
466}
467
468// ============================================================================
469// ResultMapError — 错误类型
470// ============================================================================
471
472/// ResultMap 错误
473#[derive(Debug, Clone, PartialEq)]
474pub enum ResultMapError {
475    /// ResultMap 未注册
476    MapNotFound { id: String },
477    /// 必需列缺失
478    RequiredColumnMissing { column: String },
479    /// 嵌套映射失败
480    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// ============================================================================
502// 映射函数
503// ============================================================================
504
505/// 应用 ResultMap 规则到单行,返回属性 HashMap
506///
507/// # 行为
508///
509/// 1. 检查 discriminator,若命中 case 则改用 case 指定的 ResultMap
510/// 2. 应用 id_mappings 和 result_mappings,将列值填入属性
511/// 3. 递归处理 associations(一对一)
512/// 4. 单行模式下 collections 仅返回当前行解析出的单个子实体(多次行合并需用 `apply_result_map_many`)
513#[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    // 1. discriminator 多态分派
526    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    // 2. id + result 映射
543    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    // 3. associations(一对一,递归)
555    for assoc in &effective_map.associations {
556        // notNullColumn 检查
557        if let Some(not_null_col) = &assoc.not_null_column {
558            if !row.is_not_null(not_null_col) {
559                continue; // 跳过,不填充该 association
560            }
561        }
562
563        // 根据 column_prefix 决定传入的 RowData(只调用一次 apply_result_map)
564        let nested_value = if let Some(prefix) = &assoc.column_prefix {
565            // prefix 模式:构造去除前缀的 RowData 后递归
566            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            // 无 prefix:直接用原始 row 递归
580            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        // 将嵌套 HashMap 转为 Value::Object 存储
589        attrs.insert(assoc.property.clone(), Value::Object(nested_value));
590    }
591
592    // 4. collections(一对多,单行模式下仅返回当前行解析的单个元素)
593    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        // collection 在单行模式下以单元素 Array 形式返回
623        // 完整合并需调用 apply_result_map_many
624        attrs.insert(
625            coll.property.clone(),
626            Value::Array(vec![Value::Object(nested)]),
627        );
628    }
629
630    Ok(attrs)
631}
632
633/// 应用 ResultMap 到多行,处理 collection 聚合
634///
635/// # 行为
636///
637/// 1. 按主键(id_mappings 的属性值)分组:同一主键的多行合并为一个实体
638/// 2. associations 取第一行解析结果
639/// 3. collections 跨行聚合:每行解析出的子实体追加到数组
640#[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    // 用主键属性值的字符串形式作为分组的 key
657    fn pk_key(attrs: &HashMap<String, Value>, id_mappings: &[Mapping]) -> String {
658        if id_mappings.is_empty() {
659            // 无主键映射时,按行号分组(每行独立)
660            // 这里返回空字符串,调用方需另行处理
661            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    // 保持插入顺序
675    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        // 聚合 collections
690        for coll in &map.collections {
691            if let Some(Value::Array(items)) = attrs.get(&coll.property) {
692                if !items.is_empty() {
693                    let acc = collection_acc.get_mut(&key).ok_or_else(|| {
694                        ResultMapError::NestedMappingFailed {
695                            property: "collection_acc".to_string(),
696                            reason: format!("key '{}' not found in collection_acc", key),
697                        }
698                    })?;
699                    let entry = acc.entry(coll.property.clone()).or_default();
700                    for item in items {
701                        entry.push(item.clone());
702                    }
703                }
704            }
705        }
706    }
707
708    // 合并 collection 聚合结果到主属性
709    let mut result = Vec::new();
710    for key in ordered_keys {
711        let mut attrs = groups
712            .remove(&key)
713            .ok_or_else(|| ResultMapError::NestedMappingFailed {
714                property: "groups".to_string(),
715                reason: format!("key '{}' not found in groups", key),
716            })?;
717        if let Some(coll_acc) = collection_acc.remove(&key) {
718            for (prop, items) in coll_acc {
719                attrs.insert(prop, Value::Array(items));
720            }
721        }
722        result.push(attrs);
723    }
724
725    Ok(result)
726}
727
728// ============================================================================
729// NativeQuery + ResultSetMapping
730// ============================================================================
731
732/// 标量结果列
733#[derive(Debug, Clone, PartialEq, Eq)]
734pub struct ScalarResult {
735    /// 列名
736    pub column: String,
737    /// 类型名(如 "i64"、"string")
738    pub type_name: String,
739}
740
741impl ScalarResult {
742    pub fn new(column: impl Into<String>, type_name: impl Into<String>) -> Self {
743        Self {
744            column: column.into(),
745            type_name: type_name.into(),
746        }
747    }
748}
749
750/// 实体字段结果
751#[derive(Debug, Clone, PartialEq, Eq)]
752pub struct FieldResult {
753    pub name: String,
754    pub column: String,
755}
756
757impl FieldResult {
758    pub fn new(name: impl Into<String>, column: impl Into<String>) -> Self {
759        Self {
760            name: name.into(),
761            column: column.into(),
762        }
763    }
764}
765
766/// Entity 结果(用于 ResultSetMapping)
767#[derive(Debug, Clone, PartialEq, Eq)]
768pub struct EntityResult {
769    pub entity_class: String,
770    pub fields: Vec<FieldResult>,
771    pub discriminator_column: Option<String>,
772}
773
774impl EntityResult {
775    pub fn new(entity_class: impl Into<String>) -> Self {
776        Self {
777            entity_class: entity_class.into(),
778            fields: Vec::new(),
779            discriminator_column: None,
780        }
781    }
782
783    pub fn add_field(&mut self, field: FieldResult) -> &mut Self {
784        self.fields.push(field);
785        self
786    }
787
788    pub fn with_discriminator_column(mut self, col: impl Into<String>) -> Self {
789        self.discriminator_column = Some(col.into());
790        self
791    }
792}
793
794/// Hibernate `@SqlResultSetMapping` 风格的结果集映射
795#[derive(Debug, Clone, PartialEq)]
796pub struct ResultSetMapping {
797    pub name: String,
798    pub entities: Vec<EntityResult>,
799    pub scalars: Vec<ScalarResult>,
800}
801
802impl ResultSetMapping {
803    pub fn new(name: impl Into<String>) -> Self {
804        Self {
805            name: name.into(),
806            entities: Vec::new(),
807            scalars: Vec::new(),
808        }
809    }
810
811    pub fn add_entity(&mut self, entity: EntityResult) -> &mut Self {
812        self.entities.push(entity);
813        self
814    }
815
816    pub fn add_scalar(&mut self, scalar: ScalarResult) -> &mut Self {
817        self.scalars.push(scalar);
818        self
819    }
820}
821
822/// ResultSetMapping 注册中心
823#[derive(Debug, Default)]
824pub struct ResultSetMappingRegistry {
825    mappings: RwLock<HashMap<String, ResultSetMapping>>,
826}
827
828impl ResultSetMappingRegistry {
829    pub fn new() -> Self {
830        Self {
831            mappings: RwLock::new(HashMap::new()),
832        }
833    }
834
835    pub fn register(&self, mapping: ResultSetMapping) {
836        let mut m = self.mappings.write();
837        m.insert(mapping.name.clone(), mapping);
838    }
839
840    pub fn get(&self, name: &str) -> Option<ResultSetMapping> {
841        let m = self.mappings.read();
842        m.get(name).cloned()
843    }
844
845    pub fn contains(&self, name: &str) -> bool {
846        let m = self.mappings.read();
847        m.contains_key(name)
848    }
849
850    pub fn len(&self) -> usize {
851        let m = self.mappings.read();
852        m.len()
853    }
854
855    pub fn is_empty(&self) -> bool {
856        self.len() == 0
857    }
858}
859
860/// NativeQuery — 原生 SQL + ResultSetMapping
861#[derive(Debug, Clone)]
862pub struct NativeQuery {
863    /// SQL 语句(可含 `?` 占位符)
864    pub sql: String,
865    /// ResultSetMapping 名称
866    pub result_set_mapping: String,
867    /// 绑定参数
868    pub parameters: Vec<Value>,
869}
870
871impl NativeQuery {
872    pub fn new(sql: impl Into<String>, mapping_name: impl Into<String>) -> Self {
873        Self {
874            sql: sql.into(),
875            result_set_mapping: mapping_name.into(),
876            parameters: Vec::new(),
877        }
878    }
879
880    pub fn bind(&mut self, value: Value) -> &mut Self {
881        self.parameters.push(value);
882        self
883    }
884
885    pub fn bind_many(&mut self, values: Vec<Value>) -> &mut Self {
886        self.parameters.extend(values);
887        self
888    }
889}
890
891/// 应用 ResultSetMapping 到单行,返回 (entity_attrs_vec, scalar_values_vec)
892///
893/// 返回:
894/// - 第一个 Vec:每个 EntityResult 对应一个 HashMap<String, Value>
895/// - 第二个 Vec:每个 ScalarResult 对应一个 Value
896pub fn apply_result_set_mapping(
897    mapping: &ResultSetMapping,
898    row: &RowData,
899) -> ResultSetMappingResult {
900    let mut entities = Vec::new();
901    for ent in &mapping.entities {
902        let mut attrs = HashMap::new();
903        for f in &ent.fields {
904            if let Some(v) = row.get(&f.column) {
905                attrs.insert(f.name.clone(), v.clone());
906            }
907        }
908        entities.push(attrs);
909    }
910
911    let mut scalars = Vec::new();
912    for s in &mapping.scalars {
913        if let Some(v) = row.get(&s.column) {
914            scalars.push(v.clone());
915        } else {
916            scalars.push(Value::Null);
917        }
918    }
919
920    (entities, scalars)
921}
922
923/// ResultSetMapping 应用结果类型(entities + scalars)
924pub type ResultSetMappingResult = (Vec<HashMap<String, Value>>, Vec<Value>);
925
926/// 应用 ResultSetMapping 到多行
927pub fn apply_result_set_mapping_many(
928    mapping: &ResultSetMapping,
929    rows: &[RowData],
930) -> Vec<ResultSetMappingResult> {
931    rows.iter()
932        .map(|row| apply_result_set_mapping(mapping, row))
933        .collect()
934}
935
936// ============================================================================
937// 单元测试
938// ============================================================================
939
940#[cfg(test)]
941mod tests {
942    use super::*;
943
944    // ===== Mapping =====
945
946    #[test]
947    fn test_mapping_new() {
948        let m = Mapping::new("id", "user_id");
949        assert_eq!(m.property, "id");
950        assert_eq!(m.column, "user_id");
951        assert_eq!(m.type_handler, None);
952    }
953
954    #[test]
955    fn test_mapping_with_handler() {
956        let m = Mapping::with_handler("amount", "amount", "money_handler");
957        assert_eq!(m.property, "amount");
958        assert_eq!(m.column, "amount");
959        assert_eq!(m.type_handler.as_deref(), Some("money_handler"));
960    }
961
962    // ===== NestedAssociation =====
963
964    #[test]
965    fn test_association_new() {
966        let a = NestedAssociation::new("dept", "deptMap");
967        assert_eq!(a.property, "dept");
968        assert_eq!(a.result_map, "deptMap");
969        assert_eq!(a.column_prefix, None);
970        assert_eq!(a.not_null_column, None);
971    }
972
973    #[test]
974    fn test_association_with_prefix() {
975        let a = NestedAssociation::new("dept", "deptMap").with_prefix("d_");
976        assert_eq!(a.column_prefix.as_deref(), Some("d_"));
977    }
978
979    #[test]
980    fn test_association_with_not_null_column() {
981        let a = NestedAssociation::new("dept", "deptMap").with_not_null_column("dept_id");
982        assert_eq!(a.not_null_column.as_deref(), Some("dept_id"));
983    }
984
985    // ===== NestedCollection =====
986
987    #[test]
988    fn test_collection_new() {
989        let c = NestedCollection::new("roles", "roleMap");
990        assert_eq!(c.property, "roles");
991        assert_eq!(c.result_map, "roleMap");
992        assert_eq!(c.column_prefix, None);
993    }
994
995    #[test]
996    fn test_collection_with_prefix() {
997        let c = NestedCollection::new("roles", "roleMap").with_prefix("r_");
998        assert_eq!(c.column_prefix.as_deref(), Some("r_"));
999    }
1000
1001    // ===== Discriminator =====
1002
1003    #[test]
1004    fn test_discriminator_new() {
1005        let d = Discriminator::new("user_type");
1006        assert_eq!(d.column, "user_type");
1007        assert!(d.cases.is_empty());
1008    }
1009
1010    #[test]
1011    fn test_discriminator_add_case() {
1012        let mut d = Discriminator::new("user_type");
1013        d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"))
1014            .add_case(DiscriminatorCase::new(Value::I64(2), "userMap"));
1015        assert_eq!(d.cases.len(), 2);
1016    }
1017
1018    #[test]
1019    fn test_discriminator_resolve_hit() {
1020        let mut d = Discriminator::new("user_type");
1021        d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"))
1022            .add_case(DiscriminatorCase::new(Value::I64(2), "userMap"));
1023
1024        assert_eq!(d.resolve(&Value::I64(1)), Some("adminMap"));
1025        assert_eq!(d.resolve(&Value::I64(2)), Some("userMap"));
1026    }
1027
1028    #[test]
1029    fn test_discriminator_resolve_miss() {
1030        let mut d = Discriminator::new("user_type");
1031        d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1032
1033        assert_eq!(d.resolve(&Value::I64(99)), None);
1034    }
1035
1036    // ===== ResultMap =====
1037
1038    #[test]
1039    fn test_result_map_new() {
1040        let rm = ResultMap::new("userMap", "User");
1041        assert_eq!(rm.id, "userMap");
1042        assert_eq!(rm.type_name, "User");
1043        assert!(rm.id_mappings.is_empty());
1044        assert!(rm.result_mappings.is_empty());
1045        assert!(rm.associations.is_empty());
1046        assert!(rm.collections.is_empty());
1047        assert!(rm.discriminator.is_none());
1048    }
1049
1050    #[test]
1051    fn test_result_map_add_mappings() {
1052        let mut rm = ResultMap::new("userMap", "User");
1053        rm.add_id_mapping(Mapping::new("id", "user_id"))
1054            .add_result_mapping(Mapping::new("name", "user_name"))
1055            .add_association(NestedAssociation::new("dept", "deptMap"))
1056            .add_collection(NestedCollection::new("roles", "roleMap"));
1057
1058        assert_eq!(rm.id_mappings.len(), 1);
1059        assert_eq!(rm.result_mappings.len(), 1);
1060        assert_eq!(rm.associations.len(), 1);
1061        assert_eq!(rm.collections.len(), 1);
1062    }
1063
1064    #[test]
1065    fn test_result_map_set_discriminator() {
1066        let mut rm = ResultMap::new("userMap", "User");
1067        rm.set_discriminator(Discriminator::new("user_type"));
1068        assert!(rm.discriminator.is_some());
1069        assert_eq!(rm.discriminator.as_ref().unwrap().column, "user_type");
1070    }
1071
1072    #[test]
1073    fn test_sub_map_ids() {
1074        let mut rm = ResultMap::new("userMap", "User");
1075        rm.add_association(NestedAssociation::new("dept", "deptMap"))
1076            .add_collection(NestedCollection::new("roles", "roleMap"))
1077            .set_discriminator({
1078                let mut d = Discriminator::new("type");
1079                d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1080                d
1081            });
1082
1083        let ids = rm.sub_map_ids();
1084        assert!(ids.contains(&"deptMap".to_string()));
1085        assert!(ids.contains(&"roleMap".to_string()));
1086        assert!(ids.contains(&"adminMap".to_string()));
1087    }
1088
1089    // ===== ResultMapRegistry =====
1090
1091    #[test]
1092    fn test_registry_register_and_get() {
1093        let registry = ResultMapRegistry::new();
1094        let rm = ResultMap::new("userMap", "User");
1095        registry.register(rm);
1096
1097        assert!(registry.contains("userMap"));
1098        assert!(!registry.contains("missing"));
1099        assert_eq!(registry.len(), 1);
1100        assert!(registry.get("userMap").is_some());
1101        assert!(registry.get("missing").is_none());
1102    }
1103
1104    #[test]
1105    fn test_registry_list_ids() {
1106        let registry = ResultMapRegistry::new();
1107        registry.register(ResultMap::new("userMap", "User"));
1108        registry.register(ResultMap::new("deptMap", "Dept"));
1109
1110        let ids = registry.list_ids();
1111        assert_eq!(ids.len(), 2);
1112        assert!(ids.contains(&"userMap".to_string()));
1113        assert!(ids.contains(&"deptMap".to_string()));
1114    }
1115
1116    #[test]
1117    fn test_registry_clear() {
1118        let registry = ResultMapRegistry::new();
1119        registry.register(ResultMap::new("userMap", "User"));
1120        assert_eq!(registry.len(), 1);
1121        registry.clear();
1122        assert_eq!(registry.len(), 0);
1123    }
1124
1125    #[test]
1126    fn test_registry_overwrite() {
1127        let registry = ResultMapRegistry::new();
1128        registry.register(ResultMap::new("userMap", "User"));
1129        registry.register(ResultMap::new("userMap", "AdminUser"));
1130
1131        let rm = registry.get("userMap").unwrap();
1132        assert_eq!(rm.type_name, "AdminUser");
1133    }
1134
1135    // ===== RowData =====
1136
1137    #[test]
1138    fn test_row_data_new() {
1139        let mut cols = HashMap::new();
1140        cols.insert("id".to_string(), Value::I64(1));
1141        let row = RowData::new(cols);
1142
1143        assert_eq!(row.get("id"), Some(&Value::I64(1)));
1144        assert_eq!(row.get("missing"), None);
1145        assert_eq!(row.len(), 1);
1146    }
1147
1148    #[test]
1149    fn test_row_data_set_and_get() {
1150        let mut row = RowData::empty();
1151        row.set("name", Value::String("Alice".to_string()));
1152
1153        assert_eq!(row.get("name"), Some(&Value::String("Alice".to_string())));
1154    }
1155
1156    #[test]
1157    fn test_row_data_get_with_prefix() {
1158        let mut row = RowData::empty();
1159        row.set("dept_id", Value::I64(10));
1160        row.set("dept_name", Value::String("Engineering".to_string()));
1161
1162        assert_eq!(row.get_with_prefix("dept_", "id"), Some(&Value::I64(10)));
1163        assert_eq!(
1164            row.get_with_prefix("dept_", "name"),
1165            Some(&Value::String("Engineering".to_string()))
1166        );
1167        assert_eq!(row.get_with_prefix("dept_", "missing"), None);
1168    }
1169
1170    #[test]
1171    fn test_row_data_is_not_null() {
1172        let mut row = RowData::empty();
1173        row.set("a", Value::I64(1));
1174        row.set("b", Value::Null);
1175
1176        assert!(row.is_not_null("a"));
1177        assert!(!row.is_not_null("b"));
1178        assert!(!row.is_not_null("missing"));
1179    }
1180
1181    #[test]
1182    fn test_row_data_column_names() {
1183        let mut row = RowData::empty();
1184        row.set("id", Value::I64(1));
1185        row.set("name", Value::String("Alice".to_string()));
1186
1187        let names = row.column_names();
1188        assert_eq!(names.len(), 2);
1189        assert!(names.contains(&"id".to_string()));
1190        assert!(names.contains(&"name".to_string()));
1191    }
1192
1193    // ===== apply_result_map 基础 =====
1194
1195    #[test]
1196    fn test_apply_result_map_basic() {
1197        let registry = ResultMapRegistry::new();
1198        let mut rm = ResultMap::new("userMap", "User");
1199        rm.add_id_mapping(Mapping::new("id", "user_id"))
1200            .add_result_mapping(Mapping::new("name", "user_name"));
1201        registry.register(rm);
1202
1203        let mut row = RowData::empty();
1204        row.set("user_id", Value::I64(1));
1205        row.set("user_name", Value::String("Alice".to_string()));
1206
1207        let attrs = apply_result_map(&registry, "userMap", &row).unwrap();
1208        assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1209        assert_eq!(attrs.get("name"), Some(&Value::String("Alice".to_string())));
1210    }
1211
1212    #[test]
1213    fn test_apply_result_map_missing_column() {
1214        let registry = ResultMapRegistry::new();
1215        let mut rm = ResultMap::new("userMap", "User");
1216        rm.add_id_mapping(Mapping::new("id", "user_id"))
1217            .add_result_mapping(Mapping::new("name", "user_name"));
1218        registry.register(rm);
1219
1220        let row = RowData::empty();
1221        let attrs = apply_result_map(&registry, "userMap", &row).unwrap();
1222        // 缺失列不报错,对应属性不出现
1223        assert!(!attrs.contains_key("id"));
1224        assert!(!attrs.contains_key("name"));
1225    }
1226
1227    #[test]
1228    fn test_apply_result_map_not_found() {
1229        let registry = ResultMapRegistry::new();
1230        let row = RowData::empty();
1231        let err = apply_result_map(&registry, "missingMap", &row).unwrap_err();
1232        match err {
1233            ResultMapError::MapNotFound { id } => assert_eq!(id, "missingMap"),
1234            _ => panic!("expected MapNotFound"),
1235        }
1236    }
1237
1238    // ===== apply_result_map association =====
1239
1240    #[test]
1241    fn test_apply_result_map_with_association() {
1242        let registry = ResultMapRegistry::new();
1243
1244        let mut dept_map = ResultMap::new("deptMap", "Dept");
1245        dept_map
1246            .add_id_mapping(Mapping::new("id", "dept_id"))
1247            .add_result_mapping(Mapping::new("name", "dept_name"));
1248        registry.register(dept_map);
1249
1250        let mut user_map = ResultMap::new("userMap", "User");
1251        user_map
1252            .add_id_mapping(Mapping::new("id", "user_id"))
1253            .add_result_mapping(Mapping::new("name", "user_name"))
1254            .add_association(NestedAssociation::new("dept", "deptMap"));
1255        registry.register(user_map);
1256
1257        let mut row = RowData::empty();
1258        row.set("user_id", Value::I64(1));
1259        row.set("user_name", Value::String("Alice".to_string()));
1260        row.set("dept_id", Value::I64(10));
1261        row.set("dept_name", Value::String("Engineering".to_string()));
1262
1263        let attrs = apply_result_map(&registry, "userMap", &row).unwrap();
1264        assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1265        let dept = attrs.get("dept");
1266        assert!(dept.is_some());
1267        if let Some(Value::Object(dept_attrs)) = dept {
1268            assert_eq!(dept_attrs.get("id"), Some(&Value::I64(10)));
1269            assert_eq!(
1270                dept_attrs.get("name"),
1271                Some(&Value::String("Engineering".to_string()))
1272            );
1273        }
1274    }
1275
1276    #[test]
1277    fn test_apply_result_map_association_not_null_column_skip() {
1278        let registry = ResultMapRegistry::new();
1279
1280        let mut dept_map = ResultMap::new("deptMap", "Dept");
1281        dept_map
1282            .add_id_mapping(Mapping::new("id", "dept_id"))
1283            .add_result_mapping(Mapping::new("name", "dept_name"));
1284        registry.register(dept_map);
1285
1286        let mut user_map = ResultMap::new("userMap", "User");
1287        user_map
1288            .add_id_mapping(Mapping::new("id", "user_id"))
1289            .add_result_mapping(Mapping::new("name", "user_name"))
1290            .add_association(
1291                NestedAssociation::new("dept", "deptMap").with_not_null_column("dept_id"),
1292            );
1293        registry.register(user_map);
1294
1295        // dept_id 为 NULL(LEFT JOIN 缺失行)
1296        let mut row = RowData::empty();
1297        row.set("user_id", Value::I64(1));
1298        row.set("user_name", Value::String("Alice".to_string()));
1299        row.set("dept_id", Value::Null);
1300
1301        let attrs = apply_result_map(&registry, "userMap", &row).unwrap();
1302        // dept 应该被跳过(不出现)
1303        assert!(!attrs.contains_key("dept"));
1304    }
1305
1306    #[test]
1307    fn test_apply_result_map_association_with_prefix() {
1308        let registry = ResultMapRegistry::new();
1309
1310        let mut dept_map = ResultMap::new("deptMap", "Dept");
1311        dept_map
1312            .add_id_mapping(Mapping::new("id", "id"))
1313            .add_result_mapping(Mapping::new("name", "name"));
1314        registry.register(dept_map);
1315
1316        let mut user_map = ResultMap::new("userMap", "User");
1317        user_map
1318            .add_id_mapping(Mapping::new("id", "id"))
1319            .add_result_mapping(Mapping::new("name", "name"))
1320            .add_association(NestedAssociation::new("dept", "deptMap").with_prefix("d_"));
1321        registry.register(user_map);
1322
1323        // 列名带 d_ 前缀
1324        let mut row = RowData::empty();
1325        row.set("id", Value::I64(1));
1326        row.set("name", Value::String("Alice".to_string()));
1327        row.set("d_id", Value::I64(10));
1328        row.set("d_name", Value::String("Engineering".to_string()));
1329
1330        let attrs = apply_result_map(&registry, "userMap", &row).unwrap();
1331        assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1332        assert_eq!(attrs.get("name"), Some(&Value::String("Alice".to_string())));
1333
1334        if let Some(Value::Object(dept_attrs)) = attrs.get("dept") {
1335            assert_eq!(dept_attrs.get("id"), Some(&Value::I64(10)));
1336            assert_eq!(
1337                dept_attrs.get("name"),
1338                Some(&Value::String("Engineering".to_string()))
1339            );
1340        } else {
1341            panic!("dept should be an Object");
1342        }
1343    }
1344
1345    // ===== apply_result_map discriminator =====
1346
1347    #[test]
1348    fn test_apply_result_map_discriminator() {
1349        let registry = ResultMapRegistry::new();
1350
1351        // adminMap
1352        let mut admin_map = ResultMap::new("adminMap", "AdminUser");
1353        admin_map
1354            .add_id_mapping(Mapping::new("id", "user_id"))
1355            .add_result_mapping(Mapping::new("name", "user_name"))
1356            .add_result_mapping(Mapping::new("admin_level", "extra_level"));
1357        registry.register(admin_map);
1358
1359        // normalMap
1360        let mut normal_map = ResultMap::new("normalMap", "NormalUser");
1361        normal_map
1362            .add_id_mapping(Mapping::new("id", "user_id"))
1363            .add_result_mapping(Mapping::new("name", "user_name"));
1364        registry.register(normal_map);
1365
1366        // baseMap with discriminator
1367        let mut base_map = ResultMap::new("baseMap", "User");
1368        base_map
1369            .add_id_mapping(Mapping::new("id", "user_id"))
1370            .add_result_mapping(Mapping::new("name", "user_name"))
1371            .set_discriminator({
1372                let mut d = Discriminator::new("user_type");
1373                d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1374                d.add_case(DiscriminatorCase::new(Value::I64(2), "normalMap"));
1375                d
1376            });
1377        registry.register(base_map);
1378
1379        // user_type=1 → adminMap
1380        let mut row = RowData::empty();
1381        row.set("user_id", Value::I64(1));
1382        row.set("user_name", Value::String("Alice".to_string()));
1383        row.set("user_type", Value::I64(1));
1384        row.set("extra_level", Value::I64(5));
1385
1386        let attrs = apply_result_map(&registry, "baseMap", &row).unwrap();
1387        assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1388        assert_eq!(attrs.get("admin_level"), Some(&Value::I64(5)));
1389
1390        // user_type=2 → normalMap
1391        let mut row2 = RowData::empty();
1392        row2.set("user_id", Value::I64(2));
1393        row2.set("user_name", Value::String("Bob".to_string()));
1394        row2.set("user_type", Value::I64(2));
1395
1396        let attrs2 = apply_result_map(&registry, "baseMap", &row2).unwrap();
1397        assert_eq!(attrs2.get("id"), Some(&Value::I64(2)));
1398        assert!(!attrs2.contains_key("admin_level")); // normalMap 没有 admin_level
1399    }
1400
1401    #[test]
1402    fn test_apply_result_map_discriminator_no_match_falls_back_to_base() {
1403        let registry = ResultMapRegistry::new();
1404
1405        let mut base_map = ResultMap::new("baseMap", "User");
1406        base_map
1407            .add_id_mapping(Mapping::new("id", "user_id"))
1408            .set_discriminator({
1409                let mut d = Discriminator::new("user_type");
1410                d.add_case(DiscriminatorCase::new(Value::I64(1), "adminMap"));
1411                d
1412            });
1413        registry.register(base_map);
1414
1415        // user_type=99 → 无匹配,使用 baseMap
1416        let mut row = RowData::empty();
1417        row.set("user_id", Value::I64(1));
1418        row.set("user_type", Value::I64(99));
1419
1420        let attrs = apply_result_map(&registry, "baseMap", &row).unwrap();
1421        assert_eq!(attrs.get("id"), Some(&Value::I64(1)));
1422    }
1423
1424    // ===== apply_result_map_many collection 聚合 =====
1425
1426    #[test]
1427    fn test_apply_result_map_many_collection_aggregation() {
1428        let registry = ResultMapRegistry::new();
1429
1430        let mut role_map = ResultMap::new("roleMap", "Role");
1431        role_map
1432            .add_id_mapping(Mapping::new("id", "role_id"))
1433            .add_result_mapping(Mapping::new("name", "role_name"));
1434        registry.register(role_map);
1435
1436        let mut user_map = ResultMap::new("userMap", "User");
1437        user_map
1438            .add_id_mapping(Mapping::new("id", "user_id"))
1439            .add_result_mapping(Mapping::new("name", "user_name"))
1440            .add_collection(NestedCollection::new("roles", "roleMap"));
1441        registry.register(user_map);
1442
1443        // 用户 1 有 2 个角色
1444        let rows = vec![
1445            {
1446                let mut r = RowData::empty();
1447                r.set("user_id", Value::I64(1));
1448                r.set("user_name", Value::String("Alice".to_string()));
1449                r.set("role_id", Value::I64(100));
1450                r.set("role_name", Value::String("admin".to_string()));
1451                r
1452            },
1453            {
1454                let mut r = RowData::empty();
1455                r.set("user_id", Value::I64(1));
1456                r.set("user_name", Value::String("Alice".to_string()));
1457                r.set("role_id", Value::I64(101));
1458                r.set("role_name", Value::String("editor".to_string()));
1459                r
1460            },
1461        ];
1462
1463        let result = apply_result_map_many(&registry, "userMap", &rows).unwrap();
1464        assert_eq!(result.len(), 1); // 合并为 1 个用户
1465        let user = &result[0];
1466        assert_eq!(user.get("id"), Some(&Value::I64(1)));
1467        let roles = user.get("roles");
1468        assert!(roles.is_some());
1469        if let Some(Value::Array(items)) = roles {
1470            assert_eq!(items.len(), 2);
1471        }
1472    }
1473
1474    #[test]
1475    fn test_apply_result_map_many_multi_users() {
1476        let registry = ResultMapRegistry::new();
1477
1478        let mut role_map = ResultMap::new("roleMap", "Role");
1479        role_map
1480            .add_id_mapping(Mapping::new("id", "role_id"))
1481            .add_result_mapping(Mapping::new("name", "role_name"));
1482        registry.register(role_map);
1483
1484        let mut user_map = ResultMap::new("userMap", "User");
1485        user_map
1486            .add_id_mapping(Mapping::new("id", "user_id"))
1487            .add_result_mapping(Mapping::new("name", "user_name"))
1488            .add_collection(NestedCollection::new("roles", "roleMap"));
1489        registry.register(user_map);
1490
1491        let rows = vec![
1492            {
1493                let mut r = RowData::empty();
1494                r.set("user_id", Value::I64(1));
1495                r.set("user_name", Value::String("Alice".to_string()));
1496                r.set("role_id", Value::I64(100));
1497                r.set("role_name", Value::String("admin".to_string()));
1498                r
1499            },
1500            {
1501                let mut r = RowData::empty();
1502                r.set("user_id", Value::I64(2));
1503                r.set("user_name", Value::String("Bob".to_string()));
1504                r.set("role_id", Value::I64(101));
1505                r.set("role_name", Value::String("editor".to_string()));
1506                r
1507            },
1508        ];
1509
1510        let result = apply_result_map_many(&registry, "userMap", &rows).unwrap();
1511        assert_eq!(result.len(), 2);
1512        // 保持插入顺序
1513        assert_eq!(result[0].get("id"), Some(&Value::I64(1)));
1514        assert_eq!(result[1].get("id"), Some(&Value::I64(2)));
1515    }
1516
1517    #[test]
1518    fn test_apply_result_map_many_empty() {
1519        let registry = ResultMapRegistry::new();
1520        registry.register(ResultMap::new("userMap", "User"));
1521
1522        let result = apply_result_map_many(&registry, "userMap", &[]).unwrap();
1523        assert!(result.is_empty());
1524    }
1525
1526    // ===== ResultSetMapping =====
1527
1528    #[test]
1529    fn test_entity_result_new() {
1530        let er = EntityResult::new("User");
1531        assert_eq!(er.entity_class, "User");
1532        assert!(er.fields.is_empty());
1533        assert_eq!(er.discriminator_column, None);
1534    }
1535
1536    #[test]
1537    fn test_entity_result_add_field() {
1538        let mut er = EntityResult::new("User");
1539        er.add_field(FieldResult::new("id", "user_id"))
1540            .add_field(FieldResult::new("name", "user_name"));
1541        assert_eq!(er.fields.len(), 2);
1542    }
1543
1544    #[test]
1545    fn test_entity_result_with_discriminator() {
1546        let er = EntityResult::new("User").with_discriminator_column("user_type");
1547        assert_eq!(er.discriminator_column.as_deref(), Some("user_type"));
1548    }
1549
1550    #[test]
1551    fn test_scalar_result_new() {
1552        let s = ScalarResult::new("count", "i64");
1553        assert_eq!(s.column, "count");
1554        assert_eq!(s.type_name, "i64");
1555    }
1556
1557    #[test]
1558    fn test_result_set_mapping_new() {
1559        let rsm = ResultSetMapping::new("userCount");
1560        assert_eq!(rsm.name, "userCount");
1561        assert!(rsm.entities.is_empty());
1562        assert!(rsm.scalars.is_empty());
1563    }
1564
1565    #[test]
1566    fn test_result_set_mapping_add() {
1567        let mut rsm = ResultSetMapping::new("userWithCount");
1568        rsm.add_entity(EntityResult::new("User"))
1569            .add_scalar(ScalarResult::new("total", "i64"));
1570        assert_eq!(rsm.entities.len(), 1);
1571        assert_eq!(rsm.scalars.len(), 1);
1572    }
1573
1574    // ===== ResultSetMappingRegistry =====
1575
1576    #[test]
1577    fn test_rsm_registry() {
1578        let reg = ResultSetMappingRegistry::new();
1579        reg.register(ResultSetMapping::new("mapping1"));
1580        assert!(reg.contains("mapping1"));
1581        assert!(!reg.contains("missing"));
1582        assert_eq!(reg.len(), 1);
1583        assert!(reg.get("mapping1").is_some());
1584        assert!(reg.get("missing").is_none());
1585    }
1586
1587    // ===== NativeQuery =====
1588
1589    #[test]
1590    fn test_native_query_new() {
1591        let nq = NativeQuery::new("SELECT * FROM users WHERE id = ?", "userMapping");
1592        assert_eq!(nq.sql, "SELECT * FROM users WHERE id = ?");
1593        assert_eq!(nq.result_set_mapping, "userMapping");
1594        assert!(nq.parameters.is_empty());
1595    }
1596
1597    #[test]
1598    fn test_native_query_bind() {
1599        let mut nq = NativeQuery::new("SELECT * FROM users WHERE id = ?", "userMapping");
1600        nq.bind(Value::I64(1));
1601        assert_eq!(nq.parameters.len(), 1);
1602        assert_eq!(nq.parameters[0], Value::I64(1));
1603    }
1604
1605    #[test]
1606    fn test_native_query_bind_many() {
1607        let mut nq = NativeQuery::new("SELECT * FROM users WHERE id IN (?, ?)", "userMapping");
1608        nq.bind_many(vec![Value::I64(1), Value::I64(2)]);
1609        assert_eq!(nq.parameters.len(), 2);
1610    }
1611
1612    // ===== apply_result_set_mapping =====
1613
1614    #[test]
1615    fn test_apply_result_set_mapping_entities_only() {
1616        let mut rsm = ResultSetMapping::new("userMapping");
1617        let mut er = EntityResult::new("User");
1618        er.add_field(FieldResult::new("id", "user_id"))
1619            .add_field(FieldResult::new("name", "user_name"));
1620        rsm.add_entity(er);
1621
1622        let mut row = RowData::empty();
1623        row.set("user_id", Value::I64(1));
1624        row.set("user_name", Value::String("Alice".to_string()));
1625
1626        let (entities, scalars) = apply_result_set_mapping(&rsm, &row);
1627        assert_eq!(entities.len(), 1);
1628        assert_eq!(entities[0].get("id"), Some(&Value::I64(1)));
1629        assert_eq!(
1630            entities[0].get("name"),
1631            Some(&Value::String("Alice".to_string()))
1632        );
1633        assert!(scalars.is_empty());
1634    }
1635
1636    #[test]
1637    fn test_apply_result_set_mapping_scalars_only() {
1638        let mut rsm = ResultSetMapping::new("countMapping");
1639        rsm.add_scalar(ScalarResult::new("total", "i64"))
1640            .add_scalar(ScalarResult::new("avg_age", "f64"));
1641
1642        let mut row = RowData::empty();
1643        row.set("total", Value::I64(100));
1644        row.set("avg_age", Value::F64(25.5));
1645
1646        let (entities, scalars) = apply_result_set_mapping(&rsm, &row);
1647        assert!(entities.is_empty());
1648        assert_eq!(scalars.len(), 2);
1649        assert_eq!(scalars[0], Value::I64(100));
1650        assert_eq!(scalars[1], Value::F64(25.5));
1651    }
1652
1653    #[test]
1654    fn test_apply_result_set_mapping_mixed() {
1655        let mut rsm = ResultSetMapping::new("userWithCount");
1656        let mut er = EntityResult::new("User");
1657        er.add_field(FieldResult::new("id", "user_id"))
1658            .add_field(FieldResult::new("name", "user_name"));
1659        rsm.add_entity(er);
1660        rsm.add_scalar(ScalarResult::new("total_orders", "i64"));
1661
1662        let mut row = RowData::empty();
1663        row.set("user_id", Value::I64(1));
1664        row.set("user_name", Value::String("Alice".to_string()));
1665        row.set("total_orders", Value::I64(42));
1666
1667        let (entities, scalars) = apply_result_set_mapping(&rsm, &row);
1668        assert_eq!(entities.len(), 1);
1669        assert_eq!(scalars.len(), 1);
1670        assert_eq!(entities[0].get("id"), Some(&Value::I64(1)));
1671        assert_eq!(scalars[0], Value::I64(42));
1672    }
1673
1674    #[test]
1675    fn test_apply_result_set_mapping_many() {
1676        let mut rsm = ResultSetMapping::new("userMapping");
1677        let mut er = EntityResult::new("User");
1678        er.add_field(FieldResult::new("id", "user_id"));
1679        rsm.add_entity(er);
1680
1681        let rows = vec![
1682            {
1683                let mut r = RowData::empty();
1684                r.set("user_id", Value::I64(1));
1685                r
1686            },
1687            {
1688                let mut r = RowData::empty();
1689                r.set("user_id", Value::I64(2));
1690                r
1691            },
1692        ];
1693
1694        let results = apply_result_set_mapping_many(&rsm, &rows);
1695        assert_eq!(results.len(), 2);
1696        assert_eq!(results[0].0[0].get("id"), Some(&Value::I64(1)));
1697        assert_eq!(results[1].0[0].get("id"), Some(&Value::I64(2)));
1698    }
1699
1700    // ===== 端到端场景 =====
1701
1702    #[test]
1703    fn test_e2e_user_with_dept_and_roles() {
1704        let registry = ResultMapRegistry::new();
1705
1706        // roleMap
1707        let mut role_map = ResultMap::new("roleMap", "Role");
1708        role_map
1709            .add_id_mapping(Mapping::new("id", "role_id"))
1710            .add_result_mapping(Mapping::new("name", "role_name"));
1711        registry.register(role_map);
1712
1713        // deptMap
1714        let mut dept_map = ResultMap::new("deptMap", "Dept");
1715        dept_map
1716            .add_id_mapping(Mapping::new("id", "dept_id"))
1717            .add_result_mapping(Mapping::new("name", "dept_name"));
1718        registry.register(dept_map);
1719
1720        // userMap
1721        let mut user_map = ResultMap::new("userMap", "User");
1722        user_map
1723            .add_id_mapping(Mapping::new("id", "user_id"))
1724            .add_result_mapping(Mapping::new("name", "user_name"))
1725            .add_association(NestedAssociation::new("dept", "deptMap"))
1726            .add_collection(NestedCollection::new("roles", "roleMap"));
1727        registry.register(user_map);
1728
1729        // 模拟 JOIN 查询结果:1 个用户 + 1 个部门 + 2 个角色 = 2 行
1730        let rows = vec![
1731            {
1732                let mut r = RowData::empty();
1733                r.set("user_id", Value::I64(1));
1734                r.set("user_name", Value::String("Alice".to_string()));
1735                r.set("dept_id", Value::I64(10));
1736                r.set("dept_name", Value::String("Engineering".to_string()));
1737                r.set("role_id", Value::I64(100));
1738                r.set("role_name", Value::String("admin".to_string()));
1739                r
1740            },
1741            {
1742                let mut r = RowData::empty();
1743                r.set("user_id", Value::I64(1));
1744                r.set("user_name", Value::String("Alice".to_string()));
1745                r.set("dept_id", Value::I64(10));
1746                r.set("dept_name", Value::String("Engineering".to_string()));
1747                r.set("role_id", Value::I64(101));
1748                r.set("role_name", Value::String("editor".to_string()));
1749                r
1750            },
1751        ];
1752
1753        let result = apply_result_map_many(&registry, "userMap", &rows).unwrap();
1754        assert_eq!(result.len(), 1);
1755        let user = &result[0];
1756        assert_eq!(user.get("id"), Some(&Value::I64(1)));
1757        assert_eq!(user.get("name"), Some(&Value::String("Alice".to_string())));
1758
1759        // dept association
1760        if let Some(Value::Object(dept_attrs)) = user.get("dept") {
1761            assert_eq!(dept_attrs.get("id"), Some(&Value::I64(10)));
1762            assert_eq!(
1763                dept_attrs.get("name"),
1764                Some(&Value::String("Engineering".to_string()))
1765            );
1766        } else {
1767            panic!("dept should be an Object");
1768        }
1769
1770        // roles collection
1771        if let Some(Value::Array(roles)) = user.get("roles") {
1772            assert_eq!(roles.len(), 2);
1773        } else {
1774            panic!("roles should be an Array");
1775        }
1776    }
1777
1778    #[test]
1779    fn test_e2e_native_query_with_rsm() {
1780        // 模拟:SELECT u.id AS user_id, u.name AS user_name, COUNT(o.id) AS order_count
1781        // FROM users u LEFT JOIN orders o ON o.user_id = u.id
1782        // GROUP BY u.id
1783        let mut rsm = ResultSetMapping::new("userOrderCount");
1784        let mut er = EntityResult::new("User");
1785        er.add_field(FieldResult::new("id", "user_id"))
1786            .add_field(FieldResult::new("name", "user_name"));
1787        rsm.add_entity(er);
1788        rsm.add_scalar(ScalarResult::new("order_count", "i64"));
1789
1790        let mut nq = NativeQuery::new(
1791            "SELECT u.id AS user_id, u.name AS user_name, COUNT(o.id) AS order_count FROM users u LEFT JOIN orders o ON o.user_id = u.id GROUP BY u.id",
1792            "userOrderCount",
1793        );
1794        nq.bind(Value::Null); // 仅示意绑定参数
1795
1796        // 模拟 ResultSet
1797        let rows = vec![
1798            {
1799                let mut r = RowData::empty();
1800                r.set("user_id", Value::I64(1));
1801                r.set("user_name", Value::String("Alice".to_string()));
1802                r.set("order_count", Value::I64(5));
1803                r
1804            },
1805            {
1806                let mut r = RowData::empty();
1807                r.set("user_id", Value::I64(2));
1808                r.set("user_name", Value::String("Bob".to_string()));
1809                r.set("order_count", Value::I64(3));
1810                r
1811            },
1812        ];
1813
1814        let reg = ResultSetMappingRegistry::new();
1815        reg.register(rsm.clone());
1816        assert!(reg.contains("userOrderCount"));
1817
1818        let results = apply_result_set_mapping_many(&rsm, &rows);
1819        assert_eq!(results.len(), 2);
1820        assert_eq!(results[0].0[0].get("id"), Some(&Value::I64(1)));
1821        assert_eq!(results[0].1[0], Value::I64(5));
1822        assert_eq!(results[1].0[0].get("id"), Some(&Value::I64(2)));
1823        assert_eq!(results[1].1[0], Value::I64(3));
1824
1825        // 验证 NativeQuery 字段
1826        assert_eq!(nq.result_set_mapping, "userOrderCount");
1827        assert_eq!(nq.parameters.len(), 1);
1828    }
1829}