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