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