Skip to main content

sz_orm_core/
repository.rs

1//! Repository Pattern 仓储模式
2//!
3//! 对应文档 6.8 节改进项 37(Repository Pattern 仓储模式)。
4//!
5//! # 核心概念
6//!
7//! - **Repository trait**:统一的仓储接口,定义 CRUD + 分页 + 条件查询
8//! - **InMemoryRepository**:内存仓储实现(用于测试、原型、无数据库场景)
9//! - **WhereCondition / WhereOp**:查询条件
10//! - **PageResult**:分页结果
11//! - **RepositoryError**:仓储错误
12//!
13//! # 设计灵感
14//!
15//! - Doctrine `EntityRepository`
16//! - Spring Data JPA `@Repository` / `JpaRepository`
17//! - MyBatis-Plus `IService` / `BaseMapper`
18//! - Laravel Eloquent `Repository`
19//! - DDD(领域驱动设计)的 Repository 模式
20//!
21//! # 优势
22//!
23//! 1. **分层解耦**:业务层依赖 Repository 接口,不直接依赖 Model 静态方法
24//! 2. **可替换性**:同一接口可有 InMemory / SQL / NoSQL 等多种实现
25//! 3. **可测试**:单元测试用 InMemoryRepository;生产环境请直接使用 QueryBuilder + Connection
26//! 4. **统一 API**:CRUD + 分页 + 条件查询接口统一
27//!
28//! # 重要说明
29//!
30//! 本模块**仅提供 InMemoryRepository**(内存实现),**不提供 SqlRepository**。
31//! 如需基于 SQL 的仓储实现,请直接使用 `QueryBuilder` 生成 SQL 并通过
32//! `Pool::acquire()` 获取连接后执行。InMemoryRepository 主要用于单元测试与
33//! 业务逻辑原型验证,不执行任何真实 SQL。
34//!
35//! # 使用示例
36//!
37//! ```
38//! use sz_orm_core::repository::{
39//!     InMemoryRepository, Repository, WhereCondition, WhereOp, PageResult,
40//! };
41//! use sz_orm_core::Value;
42//! use std::collections::HashMap;
43//!
44//! // 假设 User 是 Model 的实现
45//! // let repo = InMemoryRepository::<User>::new();
46//! // let user = repo.find_by_id(1)?;
47//! // let adults = repo.find_by(&[WhereCondition::new("age", WhereOp::Ge, Value::I64(18))])?;
48//! ```
49
50use crate::value::Value;
51use std::fmt::Debug;
52use std::sync::RwLock;
53
54// ============================================================================
55// WhereCondition — 查询条件
56// ============================================================================
57
58/// 查询操作符
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub enum WhereOp {
61    /// `=`
62    Eq,
63    /// `!=`
64    Ne,
65    /// `>`
66    Gt,
67    /// `>=`
68    Ge,
69    /// `<`
70    Lt,
71    /// `<=`
72    Le,
73    /// `LIKE`
74    Like,
75    /// `IN`
76    In,
77    /// `NOT IN`
78    NotIn,
79    /// `IS NULL`
80    IsNull,
81    /// `IS NOT NULL`
82    IsNotNull,
83    /// `BETWEEN`
84    Between,
85}
86
87impl WhereOp {
88    /// 操作符名称
89    pub fn name(&self) -> &'static str {
90        match self {
91            WhereOp::Eq => "eq",
92            WhereOp::Ne => "ne",
93            WhereOp::Gt => "gt",
94            WhereOp::Ge => "ge",
95            WhereOp::Lt => "lt",
96            WhereOp::Le => "le",
97            WhereOp::Like => "like",
98            WhereOp::In => "in",
99            WhereOp::NotIn => "not_in",
100            WhereOp::IsNull => "is_null",
101            WhereOp::IsNotNull => "is_not_null",
102            WhereOp::Between => "between",
103        }
104    }
105}
106
107/// 查询条件
108#[derive(Debug, Clone)]
109pub struct WhereCondition {
110    /// 字段名
111    pub field: String,
112    /// 操作符
113    pub op: WhereOp,
114    /// 比较值
115    pub value: Value,
116    /// For Between / In / NotIn,副值列表
117    pub extra_values: Vec<Value>,
118}
119
120impl WhereCondition {
121    /// 创建单值条件(Eq/Ne/Gt/Ge/Lt/Le/Like)
122    pub fn new(field: impl Into<String>, op: WhereOp, value: Value) -> Self {
123        Self {
124            field: field.into(),
125            op,
126            value,
127            extra_values: Vec::new(),
128        }
129    }
130
131    /// 创建 IsNull / IsNotNull 条件
132    pub fn null_check(field: impl Into<String>, op: WhereOp) -> Self {
133        Self {
134            field: field.into(),
135            op,
136            value: Value::Null,
137            extra_values: Vec::new(),
138        }
139    }
140
141    /// 创建 In / NotIn 条件
142    pub fn in_op(field: impl Into<String>, op: WhereOp, values: Vec<Value>) -> Self {
143        Self {
144            field: field.into(),
145            op,
146            value: Value::Null,
147            extra_values: values,
148        }
149    }
150
151    /// 创建 Between 条件
152    pub fn between(field: impl Into<String>, low: Value, high: Value) -> Self {
153        Self {
154            field: field.into(),
155            op: WhereOp::Between,
156            value: low,
157            extra_values: vec![high],
158        }
159    }
160}
161
162// ============================================================================
163// PageResult — 分页结果
164// ============================================================================
165
166/// 分页结果
167#[derive(Debug, Clone)]
168pub struct PageResult<T> {
169    /// 当前页数据
170    pub items: Vec<T>,
171    /// 总记录数
172    pub total: u64,
173    /// 当前页码
174    pub page: u64,
175    /// 每页大小
176    pub page_size: u64,
177}
178
179impl<T> PageResult<T> {
180    /// 创建分页结果
181    pub fn new(items: Vec<T>, total: u64, page: u64, page_size: u64) -> Self {
182        Self {
183            items,
184            total,
185            page,
186            page_size,
187        }
188    }
189
190    /// 总页数
191    pub fn total_pages(&self) -> u64 {
192        if self.page_size == 0 {
193            return 0;
194        }
195        self.total.div_ceil(self.page_size)
196    }
197
198    /// 是否有下一页
199    pub fn has_next(&self) -> bool {
200        self.page < self.total_pages()
201    }
202
203    /// 是否有上一页
204    pub fn has_prev(&self) -> bool {
205        self.page > 1
206    }
207
208    /// 是否为空
209    pub fn is_empty(&self) -> bool {
210        self.items.is_empty()
211    }
212
213    /// 当前页条数
214    pub fn len(&self) -> usize {
215        self.items.len()
216    }
217
218    /// 映射为其他类型
219    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> PageResult<U> {
220        PageResult {
221            items: self.items.into_iter().map(f).collect(),
222            total: self.total,
223            page: self.page,
224            page_size: self.page_size,
225        }
226    }
227}
228
229// ============================================================================
230// BatchUpdateResult — 批量更新结果(S-1:SeaORM 对标短板补全)
231// ============================================================================
232
233/// 批量更新结果
234///
235/// 由 [`Repository::batch_update`] 返回,
236/// 区分成功更新的实体与因主键不存在而被跳过的实体数量。
237///
238/// # 字段
239///
240/// - `updated`:成功更新的实体列表(按主键匹配命中并完成 UPDATE)
241/// - `skipped`:主键不存在而被跳过的实体数量
242///
243/// # 设计动机
244///
245/// SeaORM 的 `update_many` 不区分"存在"与"不存在",只返回受影响行数。
246/// 本结构明确区分两者,便于调用方感知部分失败(如批量同步外部数据时
247/// 部分记录已被删除)并采取补偿措施(记录日志、重试插入等)。
248#[derive(Debug, Clone)]
249pub struct BatchUpdateResult<E> {
250    /// 成功更新的实体列表
251    pub updated: Vec<E>,
252    /// 主键不存在而被跳过的实体数量
253    pub skipped: usize,
254}
255
256impl<E> BatchUpdateResult<E> {
257    /// 创建批量更新结果
258    pub fn new(updated: Vec<E>, skipped: usize) -> Self {
259        Self { updated, skipped }
260    }
261
262    /// 成功更新数量
263    pub fn updated_count(&self) -> usize {
264        self.updated.len()
265    }
266
267    /// 是否有跳过的实体
268    pub fn has_skipped(&self) -> bool {
269        self.skipped > 0
270    }
271
272    /// 是否全部成功(无跳过)
273    pub fn all_updated(&self) -> bool {
274        self.skipped == 0
275    }
276
277    /// 总计处理数量(已更新 + 跳过)
278    pub fn total(&self) -> usize {
279        self.updated.len() + self.skipped
280    }
281
282    /// 映射已更新实体为其他类型(保留 skipped 计数)
283    pub fn map<U, F: Fn(E) -> U>(self, f: F) -> BatchUpdateResult<U> {
284        BatchUpdateResult {
285            updated: self.updated.into_iter().map(f).collect(),
286            skipped: self.skipped,
287        }
288    }
289}
290
291impl<E> Default for BatchUpdateResult<E> {
292    fn default() -> Self {
293        Self {
294            updated: Vec::new(),
295            skipped: 0,
296        }
297    }
298}
299
300// ============================================================================
301// RepositoryError — 错误类型
302// ============================================================================
303
304/// Repository 错误
305#[derive(Debug, Clone, PartialEq)]
306pub enum RepositoryError {
307    /// 实体未找到
308    NotFound,
309    /// 数据库错误
310    DatabaseError(String),
311    /// 实体无效(如缺主键)
312    InvalidEntity(String),
313    /// 其他错误
314    Other(String),
315}
316
317impl std::fmt::Display for RepositoryError {
318    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
319        match self {
320            RepositoryError::NotFound => write!(f, "entity not found"),
321            RepositoryError::DatabaseError(msg) => write!(f, "database error: {}", msg),
322            RepositoryError::InvalidEntity(msg) => write!(f, "invalid entity: {}", msg),
323            RepositoryError::Other(msg) => write!(f, "repository error: {}", msg),
324        }
325    }
326}
327
328impl std::error::Error for RepositoryError {}
329
330/// Repository 结果类型
331pub type RepositoryResult<T> = Result<T, RepositoryError>;
332
333// ============================================================================
334// Repository trait — 仓储接口
335// ============================================================================
336
337/// 仓储接口(generic over Model-like entity E, primary key K)
338///
339/// E 不必是 `Model` trait 实现,仅需满足存储基本要求。
340/// 这样设计允许存储任意结构(DTO、聚合、领域实体等)。
341pub trait Repository<E>: Send + Sync {
342    /// 主键类型
343    type Key: Clone + Debug + PartialEq + Send + Sync;
344
345    /// 提取实体的主键
346    fn key_of(&self, entity: &E) -> Self::Key;
347
348    /// 按主键查找
349    fn find_by_id(&self, key: &Self::Key) -> RepositoryResult<Option<E>>;
350
351    /// 查询所有
352    fn find_all(&self) -> RepositoryResult<Vec<E>>;
353
354    /// 按条件查询
355    fn find_by(&self, conditions: &[WhereCondition]) -> RepositoryResult<Vec<E>>;
356
357    /// 按条件查询单条
358    fn find_one_by(&self, conditions: &[WhereCondition]) -> RepositoryResult<Option<E>> {
359        let mut items = self.find_by(conditions)?;
360        if items.is_empty() {
361            Ok(None)
362        } else {
363            Ok(Some(items.remove(0)))
364        }
365    }
366
367    /// 保存(INSERT 或 UPDATE)
368    ///
369    /// 返回保存后的实体(可能是克隆,主键可能被填充)
370    fn save(&self, entity: E) -> RepositoryResult<E>;
371
372    /// 批量保存
373    fn save_many(&self, entities: Vec<E>) -> RepositoryResult<Vec<E>> {
374        let mut saved = Vec::with_capacity(entities.len());
375        for e in entities {
376            saved.push(self.save(e)?);
377        }
378        Ok(saved)
379    }
380
381    /// 批量更新(S-1:SeaORM 对标短板补全)
382    ///
383    /// 仅更新已存在的实体(按主键匹配),不存在的实体跳过并计入 `skipped`。
384    /// 与 [`save_many`](Self::save_many) 的区别:`save_many` 是 upsert(存在则更新,不存在则插入),
385    /// `batch_update` 是纯更新(不存在则跳过)。
386    ///
387    /// 默认实现为逐条调用 [`find_by_id`](Self::find_by_id) + [`save`](Self::save),
388    /// 具体实现可重写为真正的批量 UPDATE SQL(如 `UPDATE ... SET ... WHERE id IN (...)`)。
389    ///
390    /// # 参数
391    ///
392    /// - `entities`:待更新的实体列表(主键必须已填充)
393    ///
394    /// # 返回
395    ///
396    /// - `updated`:成功更新的实体列表
397    /// - `skipped`:主键不存在而被跳过的实体数量
398    fn batch_update(&self, entities: Vec<E>) -> RepositoryResult<BatchUpdateResult<E>> {
399        let mut updated = Vec::with_capacity(entities.len());
400        let mut skipped = 0usize;
401        for e in entities {
402            let key = self.key_of(&e);
403            if self.find_by_id(&key)?.is_some() {
404                updated.push(self.save(e)?);
405            } else {
406                skipped += 1;
407            }
408        }
409        Ok(BatchUpdateResult { updated, skipped })
410    }
411
412    /// 按主键删除
413    fn delete(&self, key: &Self::Key) -> RepositoryResult<usize>;
414
415    /// 按条件删除
416    fn delete_by(&self, conditions: &[WhereCondition]) -> RepositoryResult<usize> {
417        let items = self.find_by(conditions)?;
418        let mut count = 0;
419        for item in items {
420            let key = self.key_of(&item);
421            count += self.delete(&key)?;
422        }
423        Ok(count)
424    }
425
426    /// 总数
427    fn count(&self) -> RepositoryResult<u64>;
428
429    /// 按条件计数
430    fn count_by(&self, conditions: &[WhereCondition]) -> RepositoryResult<u64> {
431        let items = self.find_by(conditions)?;
432        Ok(items.len() as u64)
433    }
434
435    /// 主键是否存在
436    fn exists(&self, key: &Self::Key) -> RepositoryResult<bool> {
437        Ok(self.find_by_id(key)?.is_some())
438    }
439
440    /// 分页查询
441    fn paginate(&self, page: u64, page_size: u64) -> RepositoryResult<PageResult<E>>
442    where
443        E: Clone,
444    {
445        let all = self.find_all()?;
446        let total = all.len() as u64;
447        let start = ((page.saturating_sub(1)) * page_size) as usize;
448        let end = (start + page_size as usize).min(all.len());
449
450        let items = if start < all.len() {
451            all[start..end].to_vec()
452        } else {
453            Vec::new()
454        };
455
456        Ok(PageResult::new(items, total, page, page_size))
457    }
458
459    /// 按条件分页查询
460    fn paginate_by(
461        &self,
462        conditions: &[WhereCondition],
463        page: u64,
464        page_size: u64,
465    ) -> RepositoryResult<PageResult<E>>
466    where
467        E: Clone,
468    {
469        let all = self.find_by(conditions)?;
470        let total = all.len() as u64;
471        let start = ((page.saturating_sub(1)) * page_size) as usize;
472        let end = (start + page_size as usize).min(all.len());
473
474        let items = if start < all.len() {
475            all[start..end].to_vec()
476        } else {
477            Vec::new()
478        };
479
480        Ok(PageResult::new(items, total, page, page_size))
481    }
482
483    /// 按 AND 条件查询,并对结果应用额外的 OR 过滤组
484    ///
485    /// 语义:`WHERE (and1 AND and2 AND ...) AND (or1_1 OR or1_2 OR ...)`
486    ///
487    /// 用于多字段 keyword LIKE 搜索等场景(对齐 PHP ThinkPHP
488    /// `where('field1|field2|field3','like','%kw%')` 多字段 OR LIKE 语法)。
489    ///
490    /// # 默认实现
491    ///
492    /// 基于 `find_by` + 内存 OR 过滤;SQL 后端实现可重写以将 OR 下推到 SQL,
493    /// 避免 `SELECT ... WHERE app_id=?` 全表拉取后再内存过滤的性能问题。
494    ///
495    /// # 参数
496    ///
497    /// - `and`:AND 关系的条件列表(同 `find_by`)
498    /// - `or_filter`:OR 关系的条件列表,对 `and` 结果做二次过滤
499    ///
500    /// # 示例
501    ///
502    /// ```
503    /// use sz_orm_core::repository::{Repository, WhereCondition, WhereOp};
504    /// use sz_orm_core::Value;
505    /// # use sz_orm_core::repository::InMemoryRepository;
506    /// # fn example<E: sz_orm_core::repository::EntityAttributes + Clone + Send + Sync + 'static>(repo: &dyn Repository<E, Key = Value>) {
507    /// let and = vec![
508    ///     WhereCondition::new("is_delete", WhereOp::Eq, Value::I64(0)),
509    ///     WhereCondition::new("app_id", WhereOp::Eq, Value::I64(1)),
510    /// ];
511    /// let or = vec![
512    ///     WhereCondition::new("name", WhereOp::Like, Value::String("%kw%".into())),
513    ///     WhereCondition::new("addr", WhereOp::Like, Value::String("%kw%".into())),
514    /// ];
515    /// let items = repo.find_by_with_or_filter(&and, &or).unwrap();
516    /// # }
517    /// ```
518    fn find_by_with_or_filter(
519        &self,
520        and: &[WhereCondition],
521        or_filter: &[WhereCondition],
522    ) -> RepositoryResult<Vec<E>>
523    where
524        E: Clone + EntityAttributes,
525    {
526        let items = self.find_by(and)?;
527        if or_filter.is_empty() {
528            return Ok(items);
529        }
530        Ok(items
531            .into_iter()
532            .filter(|e| {
533                or_filter.iter().any(|c| {
534                    let attr = e.get_attribute(&c.field);
535                    match (attr, c.op) {
536                        (None, WhereOp::IsNull) => true,
537                        (None, _) => false,
538                        (Some(v), _) => value_matches(&v, c.op, &c.value, &c.extra_values),
539                    }
540                })
541            })
542            .collect())
543    }
544}
545
546// ============================================================================
547// InMemoryRepository — 内存仓储实现
548// ============================================================================
549
550/// 内存仓储实现
551///
552/// 使用 `Vec<E>` 存储实体,主键通过 `key_of` 提取。
553/// 适合单元测试、原型开发、无数据库场景。
554pub struct InMemoryRepository<E: Clone + Send + Sync + 'static> {
555    storage: RwLock<Vec<E>>,
556}
557
558impl<E: Clone + Send + Sync + 'static> InMemoryRepository<E> {
559    /// 创建空仓储
560    pub fn new() -> Self {
561        Self {
562            storage: RwLock::new(Vec::new()),
563        }
564    }
565
566    /// 从已有集合创建
567    pub fn from_vec(items: Vec<E>) -> Self {
568        Self {
569            storage: RwLock::new(items),
570        }
571    }
572
573    /// 当前存储条数
574    pub fn len(&self) -> usize {
575        match self.storage.read() {
576            Ok(storage) => storage.len(),
577            Err(_) => 0,
578        }
579    }
580
581    /// 是否为空
582    pub fn is_empty(&self) -> bool {
583        self.len() == 0
584    }
585
586    /// 清空
587    pub fn clear(&self) {
588        if let Ok(mut storage) = self.storage.write() {
589            storage.clear();
590        }
591    }
592}
593
594impl<E: Clone + Send + Sync + 'static> Default for InMemoryRepository<E> {
595    fn default() -> Self {
596        Self::new()
597    }
598}
599
600/// 值比较辅助函数(支持基本类型 + Value 比较)
601fn value_matches(value: &Value, op: WhereOp, target: &Value, extras: &[Value]) -> bool {
602    use Value::*;
603    match op {
604        WhereOp::Eq => value == target,
605        WhereOp::Ne => value != target,
606        WhereOp::Gt => match (value, target) {
607            (I64(a), I64(b)) => a > b,
608            (F64(a), F64(b)) => a > b,
609            (F64(a), I64(b)) => a > &(*b as f64),
610            (I64(a), F64(b)) => a > &(*b as i64),
611            (String(a), String(b)) => a > b,
612            _ => false,
613        },
614        WhereOp::Ge => match (value, target) {
615            (I64(a), I64(b)) => a >= b,
616            (F64(a), F64(b)) => a >= b,
617            (String(a), String(b)) => a >= b,
618            _ => false,
619        },
620        WhereOp::Lt => match (value, target) {
621            (I64(a), I64(b)) => a < b,
622            (F64(a), F64(b)) => a < b,
623            (String(a), String(b)) => a < b,
624            _ => false,
625        },
626        WhereOp::Le => match (value, target) {
627            (I64(a), I64(b)) => a <= b,
628            (F64(a), F64(b)) => a <= b,
629            (String(a), String(b)) => a <= b,
630            _ => false,
631        },
632        WhereOp::Like => match (value, target) {
633            (String(a), String(b)) => {
634                // 简化 LIKE:将 % 转换为 .*,其他字符转义
635                // 大小写不敏感(对齐 MySQL utf8mb4_general_ci / utf8mb4_unicode_ci 默认 collation)
636                let pattern = b.to_lowercase().replace('%', ".*").replace('_', ".");
637                let full_pattern = format!("^{}$", pattern);
638                if let Ok(re) = simple_regex::compile(&full_pattern) {
639                    re.is_match(&a.to_lowercase())
640                } else {
641                    false
642                }
643            }
644            _ => false,
645        },
646        WhereOp::In => extras.iter().any(|v| v == value),
647        WhereOp::NotIn => !extras.iter().any(|v| v == value),
648        WhereOp::IsNull => matches!(value, Null),
649        WhereOp::IsNotNull => !matches!(value, Null),
650        WhereOp::Between => {
651            if extras.is_empty() {
652                return false;
653            }
654            let low = target;
655            let high = &extras[0];
656            // value >= low AND value <= high
657            value_matches(value, WhereOp::Ge, low, &[])
658                && value_matches(value, WhereOp::Le, high, &[])
659        }
660    }
661}
662
663/// 实体属性提取 trait(用户为实体实现此 trait 以支持 find_by)
664pub trait EntityAttributes: Send + Sync {
665    /// 按字段名获取属性值
666    fn get_attribute(&self, field: &str) -> Option<Value>;
667}
668
669/// InMemoryRepository 的 EntityAttributes-based 实现
670impl<E: Clone + Send + Sync + 'static + EntityAttributes> Repository<E> for InMemoryRepository<E> {
671    type Key = Value;
672
673    fn key_of(&self, entity: &E) -> Self::Key {
674        entity.get_attribute("id").unwrap_or(Value::Null)
675    }
676
677    fn find_by_id(&self, key: &Self::Key) -> RepositoryResult<Option<E>> {
678        let storage = match self.storage.read() {
679            Ok(g) => g,
680            Err(_) => return Ok(None),
681        };
682        Ok(storage.iter().find(|e| self.key_of(e) == *key).cloned())
683    }
684
685    fn find_all(&self) -> RepositoryResult<Vec<E>> {
686        let storage = match self.storage.read() {
687            Ok(g) => g,
688            Err(_) => return Ok(Vec::new()),
689        };
690        Ok(storage.clone())
691    }
692
693    fn find_by(&self, conditions: &[WhereCondition]) -> RepositoryResult<Vec<E>> {
694        let storage = match self.storage.read() {
695            Ok(g) => g,
696            Err(_) => return Ok(Vec::new()),
697        };
698        let result: Vec<E> = storage
699            .iter()
700            .filter(|e| {
701                conditions.iter().all(|c| {
702                    let attr = e.get_attribute(&c.field);
703                    match (attr, c.op) {
704                        (None, WhereOp::IsNull) => true,
705                        (None, _) => false,
706                        (Some(v), _) => value_matches(&v, c.op, &c.value, &c.extra_values),
707                    }
708                })
709            })
710            .cloned()
711            .collect();
712        Ok(result)
713    }
714
715    fn save(&self, mut entity: E) -> RepositoryResult<E> {
716        let mut storage = match self.storage.write() {
717            Ok(g) => g,
718            Err(_) => return Ok(entity),
719        };
720        let key = self.key_of(&entity);
721
722        // 查找是否已存在
723        let existing_idx = storage.iter().position(|e| self.key_of(e) == key);
724
725        match existing_idx {
726            Some(idx) => {
727                storage[idx] = entity.clone();
728            }
729            None => {
730                storage.push(entity.clone());
731            }
732        }
733        // 注意:entity 可能被修改(如自增主键),这里返回原值
734        let _ = &mut entity; // 标记 mut 以符合签名
735        Ok(entity)
736    }
737
738    fn delete(&self, key: &Self::Key) -> RepositoryResult<usize> {
739        let mut storage = match self.storage.write() {
740            Ok(g) => g,
741            Err(_) => return Ok(0),
742        };
743        let before = storage.len();
744        storage.retain(|e| self.key_of(e) != *key);
745        Ok(before - storage.len())
746    }
747
748    fn count(&self) -> RepositoryResult<u64> {
749        Ok(self.len() as u64)
750    }
751}
752
753// ============================================================================
754// simple_regex — 极简 LIKE 模式匹配(避免引入正则依赖)
755// ============================================================================
756
757mod simple_regex {
758    /// 极简正则编译器:仅支持 `.*`、`^`、`$`、字面字符
759    pub struct Regex {
760        patterns: Vec<Pattern>,
761    }
762
763    enum Pattern {
764        AnyChars,      // .*(贪婪匹配任意字符)
765        Literal(char), // 字面字符
766        Start,         // ^
767        End,           // $
768    }
769
770    pub fn compile(pattern: &str) -> Result<Regex, String> {
771        let mut patterns = Vec::new();
772        let chars: Vec<char> = pattern.chars().collect();
773        let mut i = 0;
774        while i < chars.len() {
775            match chars[i] {
776                '^' => {
777                    patterns.push(Pattern::Start);
778                    i += 1;
779                }
780                '$' => {
781                    patterns.push(Pattern::End);
782                    i += 1;
783                }
784                '.' if i + 1 < chars.len() && chars[i + 1] == '*' => {
785                    patterns.push(Pattern::AnyChars);
786                    i += 2;
787                }
788                c => {
789                    patterns.push(Pattern::Literal(c));
790                    i += 1;
791                }
792            }
793        }
794        Ok(Regex { patterns })
795    }
796
797    impl Regex {
798        pub fn is_match(&self, text: &str) -> bool {
799            self.match_from(text, 0, 0)
800        }
801
802        fn match_from(&self, text: &str, text_idx: usize, pat_idx: usize) -> bool {
803            let chars: Vec<char> = text.chars().collect();
804            if pat_idx >= self.patterns.len() {
805                return text_idx == chars.len();
806            }
807            match &self.patterns[pat_idx] {
808                Pattern::Start => self.match_from(text, 0, pat_idx + 1),
809                Pattern::End => text_idx == chars.len(),
810                Pattern::Literal(c) => {
811                    if text_idx < chars.len() && chars[text_idx] == *c {
812                        self.match_from(text, text_idx + 1, pat_idx + 1)
813                    } else {
814                        false
815                    }
816                }
817                Pattern::AnyChars => {
818                    // 尝试匹配 0 到 len 个字符
819                    for skip in 0..=(chars.len() - text_idx) {
820                        if self.match_from(text, text_idx + skip, pat_idx + 1) {
821                            return true;
822                        }
823                    }
824                    false
825                }
826            }
827        }
828    }
829}
830
831// ============================================================================
832// GenericKeyRepository — 支持任意 Key 类型的内存仓储
833// ============================================================================
834
835/// 通用 Key 提取 trait(用户为实体实现此 trait 以支持任意 Key 类型)
836pub trait EntityKey<K>: Send + Sync {
837    /// 提取主键
838    fn key(&self) -> K;
839}
840
841/// 通用 Key 内存仓储
842pub struct GenericKeyRepository<E, K>
843where
844    E: Clone + Send + Sync + 'static,
845    K: Clone + Debug + PartialEq + Send + Sync + 'static,
846{
847    storage: RwLock<Vec<E>>,
848    _phantom: std::marker::PhantomData<K>,
849}
850
851impl<E, K> GenericKeyRepository<E, K>
852where
853    E: Clone + Send + Sync + 'static,
854    K: Clone + Debug + PartialEq + Send + Sync + 'static,
855{
856    /// 创建一个空的 `GenericKeyRepository`
857    pub fn new() -> Self {
858        Self {
859            storage: RwLock::new(Vec::new()),
860            _phantom: std::marker::PhantomData,
861        }
862    }
863
864    /// 从已有向量创建 `GenericKeyRepository`
865    pub fn from_vec(items: Vec<E>) -> Self {
866        Self {
867            storage: RwLock::new(items),
868            _phantom: std::marker::PhantomData,
869        }
870    }
871
872    /// 返回仓储中实体的数量
873    pub fn len(&self) -> usize {
874        match self.storage.read() {
875            Ok(g) => g.len(),
876            Err(_) => 0,
877        }
878    }
879
880    /// 判断仓储是否为空
881    pub fn is_empty(&self) -> bool {
882        self.len() == 0
883    }
884
885    /// 清空仓储中的所有实体
886    pub fn clear(&self) {
887        if let Ok(mut storage) = self.storage.write() {
888            storage.clear();
889        }
890    }
891}
892
893impl<E, K> Default for GenericKeyRepository<E, K>
894where
895    E: Clone + Send + Sync + 'static,
896    K: Clone + Debug + PartialEq + Send + Sync + 'static,
897{
898    fn default() -> Self {
899        Self::new()
900    }
901}
902
903impl<E, K> Repository<E> for GenericKeyRepository<E, K>
904where
905    E: Clone + Send + Sync + 'static + EntityKey<K> + EntityAttributes,
906    K: Clone + Debug + PartialEq + Send + Sync + 'static,
907{
908    type Key = K;
909
910    fn key_of(&self, entity: &E) -> Self::Key {
911        entity.key()
912    }
913
914    fn find_by_id(&self, key: &Self::Key) -> RepositoryResult<Option<E>> {
915        let storage = match self.storage.read() {
916            Ok(g) => g,
917            Err(_) => return Ok(None),
918        };
919        Ok(storage.iter().find(|e| &e.key() == key).cloned())
920    }
921
922    fn find_all(&self) -> RepositoryResult<Vec<E>> {
923        let storage = match self.storage.read() {
924            Ok(g) => g,
925            Err(_) => return Ok(Vec::new()),
926        };
927        Ok(storage.clone())
928    }
929
930    fn find_by(&self, conditions: &[WhereCondition]) -> RepositoryResult<Vec<E>> {
931        let storage = match self.storage.read() {
932            Ok(g) => g,
933            Err(_) => return Ok(Vec::new()),
934        };
935        let result: Vec<E> = storage
936            .iter()
937            .filter(|e| {
938                conditions.iter().all(|c| {
939                    let attr = e.get_attribute(&c.field);
940                    match (attr, c.op) {
941                        (None, WhereOp::IsNull) => true,
942                        (None, _) => false,
943                        (Some(v), _) => value_matches(&v, c.op, &c.value, &c.extra_values),
944                    }
945                })
946            })
947            .cloned()
948            .collect();
949        Ok(result)
950    }
951
952    fn save(&self, entity: E) -> RepositoryResult<E> {
953        let mut storage = match self.storage.write() {
954            Ok(g) => g,
955            Err(_) => return Ok(entity),
956        };
957        let key = entity.key();
958        let existing_idx = storage.iter().position(|e| e.key() == key);
959        match existing_idx {
960            Some(idx) => {
961                storage[idx] = entity.clone();
962            }
963            None => {
964                storage.push(entity.clone());
965            }
966        }
967        Ok(entity)
968    }
969
970    fn delete(&self, key: &Self::Key) -> RepositoryResult<usize> {
971        let mut storage = match self.storage.write() {
972            Ok(g) => g,
973            Err(_) => return Ok(0),
974        };
975        let before = storage.len();
976        storage.retain(|e| &e.key() != key);
977        Ok(before - storage.len())
978    }
979
980    fn count(&self) -> RepositoryResult<u64> {
981        Ok(self.len() as u64)
982    }
983}
984
985// ============================================================================
986// 单元测试
987// ============================================================================
988
989#[cfg(test)]
990mod tests {
991    use super::*;
992
993    // ===== 测试用实体 =====
994
995    #[derive(Debug, Clone, PartialEq)]
996    struct User {
997        id: i64,
998        name: String,
999        age: i64,
1000        email: String,
1001    }
1002
1003    impl User {
1004        fn new(id: i64, name: &str, age: i64, email: &str) -> Self {
1005            Self {
1006                id,
1007                name: name.to_string(),
1008                age,
1009                email: email.to_string(),
1010            }
1011        }
1012    }
1013
1014    impl EntityAttributes for User {
1015        fn get_attribute(&self, field: &str) -> Option<Value> {
1016            match field {
1017                "id" => Some(Value::I64(self.id)),
1018                "name" => Some(Value::String(self.name.clone())),
1019                "age" => Some(Value::I64(self.age)),
1020                "email" => Some(Value::String(self.email.clone())),
1021                _ => None,
1022            }
1023        }
1024    }
1025
1026    impl EntityKey<i64> for User {
1027        fn key(&self) -> i64 {
1028            self.id
1029        }
1030    }
1031
1032    // ===== WhereOp / WhereCondition =====
1033
1034    #[test]
1035    fn test_where_op_name() {
1036        assert_eq!(WhereOp::Eq.name(), "eq");
1037        assert_eq!(WhereOp::Ne.name(), "ne");
1038        assert_eq!(WhereOp::Gt.name(), "gt");
1039        assert_eq!(WhereOp::Like.name(), "like");
1040        assert_eq!(WhereOp::In.name(), "in");
1041        assert_eq!(WhereOp::IsNull.name(), "is_null");
1042        assert_eq!(WhereOp::Between.name(), "between");
1043    }
1044
1045    #[test]
1046    fn test_where_condition_new() {
1047        let c = WhereCondition::new("age", WhereOp::Ge, Value::I64(18));
1048        assert_eq!(c.field, "age");
1049        assert_eq!(c.op, WhereOp::Ge);
1050        assert_eq!(c.value, Value::I64(18));
1051        assert!(c.extra_values.is_empty());
1052    }
1053
1054    #[test]
1055    fn test_where_condition_null_check() {
1056        let c = WhereCondition::null_check("deleted_at", WhereOp::IsNull);
1057        assert_eq!(c.field, "deleted_at");
1058        assert_eq!(c.op, WhereOp::IsNull);
1059        assert_eq!(c.value, Value::Null);
1060    }
1061
1062    #[test]
1063    fn test_where_condition_in() {
1064        let c = WhereCondition::in_op(
1065            "id",
1066            WhereOp::In,
1067            vec![Value::I64(1), Value::I64(2), Value::I64(3)],
1068        );
1069        assert_eq!(c.field, "id");
1070        assert_eq!(c.op, WhereOp::In);
1071        assert_eq!(c.extra_values.len(), 3);
1072    }
1073
1074    #[test]
1075    fn test_where_condition_between() {
1076        let c = WhereCondition::between("age", Value::I64(18), Value::I64(30));
1077        assert_eq!(c.field, "age");
1078        assert_eq!(c.op, WhereOp::Between);
1079        assert_eq!(c.value, Value::I64(18));
1080        assert_eq!(c.extra_values, vec![Value::I64(30)]);
1081    }
1082
1083    // ===== PageResult =====
1084
1085    #[test]
1086    fn test_page_result_total_pages() {
1087        let pr = PageResult::new(vec![1, 2, 3], 100, 1, 10);
1088        assert_eq!(pr.total_pages(), 10);
1089    }
1090
1091    #[test]
1092    fn test_page_result_total_pages_with_remainder() {
1093        let pr: PageResult<i32> = PageResult::new(vec![], 105, 1, 10);
1094        assert_eq!(pr.total_pages(), 11);
1095    }
1096
1097    #[test]
1098    fn test_page_result_total_pages_zero_size() {
1099        let pr: PageResult<i32> = PageResult::new(vec![], 100, 1, 0);
1100        assert_eq!(pr.total_pages(), 0);
1101    }
1102
1103    #[test]
1104    fn test_page_result_has_next() {
1105        let pr = PageResult::new(vec![1, 2, 3], 100, 1, 10);
1106        assert!(pr.has_next());
1107        assert!(!pr.has_prev());
1108    }
1109
1110    #[test]
1111    fn test_page_result_has_prev() {
1112        let pr = PageResult::new(vec![1, 2, 3], 100, 5, 10);
1113        assert!(pr.has_prev());
1114        assert!(pr.has_next()); // page 5 < total_pages 10
1115    }
1116
1117    #[test]
1118    fn test_page_result_is_empty() {
1119        let pr: PageResult<i32> = PageResult::new(vec![], 0, 1, 10);
1120        assert!(pr.is_empty());
1121        assert_eq!(pr.len(), 0);
1122    }
1123
1124    #[test]
1125    fn test_page_result_map() {
1126        let pr = PageResult::new(vec![1, 2, 3], 100, 1, 10);
1127        let mapped = pr.map(|x| x * 2);
1128        assert_eq!(mapped.items, vec![2, 4, 6]);
1129        assert_eq!(mapped.total, 100);
1130    }
1131
1132    // ===== RepositoryError =====
1133
1134    #[test]
1135    fn test_repository_error_display() {
1136        let e = RepositoryError::NotFound;
1137        assert_eq!(e.to_string(), "entity not found");
1138
1139        let e = RepositoryError::DatabaseError("conn refused".to_string());
1140        assert_eq!(e.to_string(), "database error: conn refused");
1141
1142        let e = RepositoryError::InvalidEntity("missing id".to_string());
1143        assert_eq!(e.to_string(), "invalid entity: missing id");
1144
1145        let e = RepositoryError::Other("custom".to_string());
1146        assert_eq!(e.to_string(), "repository error: custom");
1147    }
1148
1149    #[test]
1150    fn test_repository_error_eq() {
1151        assert_eq!(RepositoryError::NotFound, RepositoryError::NotFound);
1152        assert_ne!(
1153            RepositoryError::NotFound,
1154            RepositoryError::Other("x".to_string())
1155        );
1156    }
1157
1158    // ===== InMemoryRepository 基础 =====
1159
1160    #[test]
1161    fn test_inmemory_create_empty() {
1162        let repo = InMemoryRepository::<User>::new();
1163        assert!(repo.is_empty());
1164        assert_eq!(repo.len(), 0);
1165    }
1166
1167    #[test]
1168    fn test_inmemory_from_vec() {
1169        let repo = InMemoryRepository::from_vec(vec![
1170            User::new(1, "Alice", 30, "alice@example.com"),
1171            User::new(2, "Bob", 25, "bob@example.com"),
1172        ]);
1173        assert_eq!(repo.len(), 2);
1174    }
1175
1176    #[test]
1177    fn test_inmemory_clear() {
1178        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1179        assert_eq!(repo.len(), 1);
1180        repo.clear();
1181        assert_eq!(repo.len(), 0);
1182    }
1183
1184    // ===== Repository trait CRUD =====
1185
1186    #[test]
1187    fn test_repo_save_and_find_by_id() {
1188        let repo = InMemoryRepository::<User>::new();
1189        let user = User::new(1, "Alice", 30, "alice@example.com");
1190        let saved = repo.save(user.clone()).unwrap();
1191        assert_eq!(saved, user);
1192
1193        let found = repo.find_by_id(&Value::I64(1)).unwrap();
1194        assert_eq!(found, Some(user));
1195    }
1196
1197    #[test]
1198    fn test_repo_find_by_id_missing() {
1199        let repo = InMemoryRepository::<User>::new();
1200        let found = repo.find_by_id(&Value::I64(999)).unwrap();
1201        assert_eq!(found, None);
1202    }
1203
1204    #[test]
1205    fn test_repo_save_many() {
1206        let repo = InMemoryRepository::<User>::new();
1207        let users = vec![
1208            User::new(1, "Alice", 30, "alice@example.com"),
1209            User::new(2, "Bob", 25, "bob@example.com"),
1210            User::new(3, "Carol", 28, "carol@example.com"),
1211        ];
1212        let saved = repo.save_many(users.clone()).unwrap();
1213        assert_eq!(saved.len(), 3);
1214        assert_eq!(repo.len(), 3);
1215    }
1216
1217    // ===== S-1: batch_update 批量更新 =====
1218
1219    #[test]
1220    fn test_batch_update_result_new() {
1221        let result = BatchUpdateResult::new(vec![1, 2, 3], 2);
1222        assert_eq!(result.updated_count(), 3);
1223        assert_eq!(result.skipped, 2);
1224        assert_eq!(result.total(), 5);
1225        assert!(result.has_skipped());
1226        assert!(!result.all_updated());
1227    }
1228
1229    #[test]
1230    fn test_batch_update_result_all_updated() {
1231        let result: BatchUpdateResult<i32> = BatchUpdateResult::new(vec![1, 2], 0);
1232        assert!(!result.has_skipped());
1233        assert!(result.all_updated());
1234        assert_eq!(result.total(), 2);
1235    }
1236
1237    #[test]
1238    fn test_batch_update_result_default() {
1239        let result: BatchUpdateResult<i32> = BatchUpdateResult::default();
1240        assert_eq!(result.updated_count(), 0);
1241        assert_eq!(result.skipped, 0);
1242        assert_eq!(result.total(), 0);
1243    }
1244
1245    #[test]
1246    fn test_batch_update_result_map() {
1247        let result = BatchUpdateResult::new(vec![1, 2, 3], 1);
1248        let mapped = result.map(|x| x * 10);
1249        assert_eq!(mapped.updated, vec![10, 20, 30]);
1250        assert_eq!(mapped.skipped, 1);
1251    }
1252
1253    #[test]
1254    fn test_repo_batch_update_all_existing() {
1255        // 所有实体都存在:全部更新,无跳过
1256        let repo = InMemoryRepository::from_vec(vec![
1257            User::new(1, "Alice", 30, "a@b.com"),
1258            User::new(2, "Bob", 25, "b@b.com"),
1259        ]);
1260        let updates = vec![
1261            User::new(1, "Alice Updated", 31, "a2@b.com"),
1262            User::new(2, "Bob Updated", 26, "b2@b.com"),
1263        ];
1264        let result = repo.batch_update(updates).unwrap();
1265        assert_eq!(result.updated_count(), 2);
1266        assert_eq!(result.skipped, 0);
1267        assert!(result.all_updated());
1268
1269        // 验证实际更新生效
1270        let alice = repo.find_by_id(&Value::I64(1)).unwrap().unwrap();
1271        assert_eq!(alice.name, "Alice Updated");
1272        assert_eq!(alice.age, 31);
1273        let bob = repo.find_by_id(&Value::I64(2)).unwrap().unwrap();
1274        assert_eq!(bob.name, "Bob Updated");
1275        assert_eq!(bob.age, 26);
1276        // 总数不变(不是插入)
1277        assert_eq!(repo.len(), 2);
1278    }
1279
1280    #[test]
1281    fn test_repo_batch_update_partial_missing() {
1282        // 部分实体不存在:仅更新存在的,跳过不存在的
1283        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1284        let updates = vec![
1285            User::new(1, "Alice Updated", 31, "a2@b.com"),
1286            User::new(999, "Ghost", 1, "ghost@b.com"), // 不存在
1287        ];
1288        let result = repo.batch_update(updates).unwrap();
1289        assert_eq!(result.updated_count(), 1);
1290        assert_eq!(result.skipped, 1);
1291        assert!(result.has_skipped());
1292
1293        // 验证存在的实体被更新
1294        let alice = repo.find_by_id(&Value::I64(1)).unwrap().unwrap();
1295        assert_eq!(alice.name, "Alice Updated");
1296        // 不存在的实体不会被插入
1297        assert!(repo.find_by_id(&Value::I64(999)).unwrap().is_none());
1298        assert_eq!(repo.len(), 1);
1299    }
1300
1301    #[test]
1302    fn test_repo_batch_update_all_missing() {
1303        // 所有实体都不存在:全部跳过
1304        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1305        let updates = vec![
1306            User::new(100, "Ghost1", 1, "g1@b.com"),
1307            User::new(200, "Ghost2", 2, "g2@b.com"),
1308        ];
1309        let result = repo.batch_update(updates).unwrap();
1310        assert_eq!(result.updated_count(), 0);
1311        assert_eq!(result.skipped, 2);
1312        assert_eq!(repo.len(), 1); // 原数据不变
1313    }
1314
1315    #[test]
1316    fn test_repo_batch_update_empty() {
1317        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1318        let result = repo.batch_update(vec![]).unwrap();
1319        assert_eq!(result.updated_count(), 0);
1320        assert_eq!(result.skipped, 0);
1321        assert_eq!(result.total(), 0);
1322    }
1323
1324    #[test]
1325    fn test_repo_batch_update_distinct_from_save_many() {
1326        // 验证 batch_update 与 save_many 语义不同:
1327        // - save_many 是 upsert(不存在的会插入)
1328        // - batch_update 是纯更新(不存在的会跳过)
1329        let repo1 = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1330        let repo2 = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1331
1332        let updates = vec![
1333            User::new(1, "Alice Updated", 31, "a2@b.com"),
1334            User::new(999, "New User", 1, "new@b.com"),
1335        ];
1336
1337        // save_many:两条都保存(id=999 会插入)
1338        let saved = repo1.save_many(updates.clone()).unwrap();
1339        assert_eq!(saved.len(), 2);
1340        assert_eq!(repo1.len(), 2); // 1 条原始 + 1 条新增
1341
1342        // batch_update:仅 id=1 更新,id=999 跳过
1343        let result = repo2.batch_update(updates).unwrap();
1344        assert_eq!(result.updated_count(), 1);
1345        assert_eq!(result.skipped, 1);
1346        assert_eq!(repo2.len(), 1); // 不增加
1347    }
1348
1349    #[test]
1350    fn test_repo_save_update_existing() {
1351        let repo = InMemoryRepository::<User>::new();
1352        repo.save(User::new(1, "Alice", 30, "alice@example.com"))
1353            .unwrap();
1354
1355        // 更新
1356        repo.save(User::new(1, "Alice Updated", 31, "alice2@example.com"))
1357            .unwrap();
1358
1359        assert_eq!(repo.len(), 1);
1360        let found = repo.find_by_id(&Value::I64(1)).unwrap().unwrap();
1361        assert_eq!(found.name, "Alice Updated");
1362        assert_eq!(found.age, 31);
1363    }
1364
1365    #[test]
1366    fn test_repo_find_all() {
1367        let repo = InMemoryRepository::from_vec(vec![
1368            User::new(1, "Alice", 30, "a@b.com"),
1369            User::new(2, "Bob", 25, "b@b.com"),
1370        ]);
1371        let all = repo.find_all().unwrap();
1372        assert_eq!(all.len(), 2);
1373    }
1374
1375    #[test]
1376    fn test_repo_find_all_empty() {
1377        let repo = InMemoryRepository::<User>::new();
1378        let all = repo.find_all().unwrap();
1379        assert!(all.is_empty());
1380    }
1381
1382    #[test]
1383    fn test_repo_delete() {
1384        let repo = InMemoryRepository::from_vec(vec![
1385            User::new(1, "Alice", 30, "a@b.com"),
1386            User::new(2, "Bob", 25, "b@b.com"),
1387        ]);
1388        let deleted = repo.delete(&Value::I64(1)).unwrap();
1389        assert_eq!(deleted, 1);
1390        assert_eq!(repo.len(), 1);
1391    }
1392
1393    #[test]
1394    fn test_repo_delete_missing() {
1395        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1396        let deleted = repo.delete(&Value::I64(999)).unwrap();
1397        assert_eq!(deleted, 0);
1398        assert_eq!(repo.len(), 1);
1399    }
1400
1401    #[test]
1402    fn test_repo_count() {
1403        let repo = InMemoryRepository::from_vec(vec![
1404            User::new(1, "Alice", 30, "a@b.com"),
1405            User::new(2, "Bob", 25, "b@b.com"),
1406            User::new(3, "Carol", 28, "c@b.com"),
1407        ]);
1408        assert_eq!(repo.count().unwrap(), 3);
1409    }
1410
1411    #[test]
1412    fn test_repo_count_empty() {
1413        let repo = InMemoryRepository::<User>::new();
1414        assert_eq!(repo.count().unwrap(), 0);
1415    }
1416
1417    #[test]
1418    fn test_repo_exists() {
1419        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1420        assert!(repo.exists(&Value::I64(1)).unwrap());
1421        assert!(!repo.exists(&Value::I64(999)).unwrap());
1422    }
1423
1424    // ===== Repository 条件查询 =====
1425
1426    #[test]
1427    fn test_repo_find_by_eq() {
1428        let repo = InMemoryRepository::from_vec(vec![
1429            User::new(1, "Alice", 30, "a@b.com"),
1430            User::new(2, "Bob", 30, "b@b.com"),
1431            User::new(3, "Carol", 25, "c@b.com"),
1432        ]);
1433
1434        let result = repo
1435            .find_by(&[WhereCondition::new("age", WhereOp::Eq, Value::I64(30))])
1436            .unwrap();
1437        assert_eq!(result.len(), 2);
1438    }
1439
1440    #[test]
1441    fn test_repo_find_by_gt() {
1442        let repo = InMemoryRepository::from_vec(vec![
1443            User::new(1, "Alice", 30, "a@b.com"),
1444            User::new(2, "Bob", 25, "b@b.com"),
1445            User::new(3, "Carol", 35, "c@b.com"),
1446        ]);
1447
1448        let result = repo
1449            .find_by(&[WhereCondition::new("age", WhereOp::Gt, Value::I64(28))])
1450            .unwrap();
1451        assert_eq!(result.len(), 2);
1452    }
1453
1454    #[test]
1455    fn test_repo_find_by_like() {
1456        let repo = InMemoryRepository::from_vec(vec![
1457            User::new(1, "Alice", 30, "alice@example.com"),
1458            User::new(2, "Bob", 25, "bob@example.com"),
1459            User::new(3, "Alicia", 28, "alicia@test.com"),
1460        ]);
1461
1462        let result = repo
1463            .find_by(&[WhereCondition::new(
1464                "name",
1465                WhereOp::Like,
1466                Value::String("Ali%".to_string()),
1467            )])
1468            .unwrap();
1469        assert_eq!(result.len(), 2);
1470    }
1471
1472    #[test]
1473    fn test_repo_find_by_like_case_insensitive() {
1474        // 对齐 MySQL utf8mb4_general_ci / utf8mb4_unicode_ci 默认 collation(大小写不敏感)
1475        let repo = InMemoryRepository::from_vec(vec![
1476            User::new(1, "Alice", 30, "alice@example.com"),
1477            User::new(2, "bob", 25, "bob@example.com"),
1478            User::new(3, "ALICIA", 28, "alicia@test.com"),
1479        ]);
1480
1481        // 小写 pattern 应匹配大小写混合的数据
1482        let result = repo
1483            .find_by(&[WhereCondition::new(
1484                "name",
1485                WhereOp::Like,
1486                Value::String("ali%".to_string()),
1487            )])
1488            .unwrap();
1489        assert_eq!(result.len(), 2, "LIKE should be case-insensitive");
1490
1491        // 大写 pattern 也应匹配小写数据
1492        let result = repo
1493            .find_by(&[WhereCondition::new(
1494                "name",
1495                WhereOp::Like,
1496                Value::String("BOB".to_string()),
1497            )])
1498            .unwrap();
1499        assert_eq!(
1500            result.len(),
1501            1,
1502            "LIKE exact match should be case-insensitive"
1503        );
1504    }
1505
1506    #[test]
1507    fn test_repo_find_by_with_or_filter_multi_field_keyword() {
1508        // 对齐 PHP ThinkPHP `where('field1|field2|field3','like','%kw%')` 多字段 OR LIKE
1509        let repo = InMemoryRepository::from_vec(vec![
1510            User::new(1, "Alice", 30, "alice@example.com"),
1511            User::new(2, "Bob", 25, "bob@example.com"),
1512            User::new(3, "Carol", 28, "carol@kw.com"), // email 含 kw
1513            User::new(4, "Dave", 32, "dave@example.com"),
1514        ]);
1515
1516        let and = vec![]; // 无 AND 条件
1517        let or = vec![
1518            WhereCondition::new("name", WhereOp::Like, Value::String("%kw%".to_string())),
1519            WhereCondition::new("email", WhereOp::Like, Value::String("%kw%".to_string())),
1520        ];
1521
1522        let result = repo.find_by_with_or_filter(&and, &or).unwrap();
1523        // 只有 Carol 的 email 含 kw
1524        assert_eq!(result.len(), 1);
1525        assert_eq!(result[0].key(), 3);
1526    }
1527
1528    #[test]
1529    fn test_repo_find_by_with_or_filter_combined_with_and() {
1530        // AND + OR 组合:对齐 PHP `where(is_delete=0 AND app_id=1) AND (name LIKE %kw% OR addr LIKE %kw%)`
1531        let repo = InMemoryRepository::from_vec(vec![
1532            User::new(1, "Alice_kw", 30, "alice@example.com"), // app_id=1, name 含 kw
1533            User::new(2, "Bob", 25, "bob@kw.com"),             // app_id=1, email 含 kw
1534            User::new(3, "Carol_kw", 28, "carol@example.com"), // app_id=2, name 含 kw(被 AND 排除)
1535            User::new(4, "Dave", 32, "dave@example.com"),      // app_id=1, 无 kw
1536        ]);
1537
1538        // User struct 没有 app_id 字段,用 age 模拟 AND 条件:age >= 28
1539        let and = vec![WhereCondition::new("age", WhereOp::Ge, Value::I64(28))];
1540        let or = vec![
1541            WhereCondition::new("name", WhereOp::Like, Value::String("%kw%".to_string())),
1542            WhereCondition::new("email", WhereOp::Like, Value::String("%kw%".to_string())),
1543        ];
1544
1545        let result = repo.find_by_with_or_filter(&and, &or).unwrap();
1546        // age >= 28: Alice(30), Carol(28), Dave(32)
1547        // 其中 name 或 email 含 kw: Alice(name), Carol(name), Bob(email 不满足 age>=28)
1548        // 但 Carol age=28 满足 >= 28,所以 Carol 也应被选中
1549        assert_eq!(result.len(), 2);
1550        let ids: Vec<i64> = result.iter().map(|u| u.key()).collect();
1551        assert!(ids.contains(&1));
1552        assert!(ids.contains(&3));
1553    }
1554
1555    #[test]
1556    fn test_repo_find_by_with_or_filter_empty_or() {
1557        // or_filter 为空时应等同于 find_by
1558        let repo = InMemoryRepository::from_vec(vec![
1559            User::new(1, "Alice", 30, "alice@example.com"),
1560            User::new(2, "Bob", 25, "bob@example.com"),
1561        ]);
1562
1563        let and = vec![WhereCondition::new("age", WhereOp::Ge, Value::I64(28))];
1564        let or: Vec<WhereCondition> = vec![];
1565
1566        let result = repo.find_by_with_or_filter(&and, &or).unwrap();
1567        assert_eq!(result.len(), 1);
1568        assert_eq!(result[0].key(), 1);
1569    }
1570
1571    #[test]
1572    fn test_repo_find_by_in() {
1573        let repo = InMemoryRepository::from_vec(vec![
1574            User::new(1, "Alice", 30, "a@b.com"),
1575            User::new(2, "Bob", 25, "b@b.com"),
1576            User::new(3, "Carol", 28, "c@b.com"),
1577            User::new(4, "Dave", 32, "d@b.com"),
1578        ]);
1579
1580        let result = repo
1581            .find_by(&[WhereCondition::in_op(
1582                "id",
1583                WhereOp::In,
1584                vec![Value::I64(1), Value::I64(3)],
1585            )])
1586            .unwrap();
1587        assert_eq!(result.len(), 2);
1588    }
1589
1590    #[test]
1591    fn test_repo_find_by_not_in() {
1592        let repo = InMemoryRepository::from_vec(vec![
1593            User::new(1, "Alice", 30, "a@b.com"),
1594            User::new(2, "Bob", 25, "b@b.com"),
1595            User::new(3, "Carol", 28, "c@b.com"),
1596        ]);
1597
1598        let result = repo
1599            .find_by(&[WhereCondition::in_op(
1600                "id",
1601                WhereOp::NotIn,
1602                vec![Value::I64(1)],
1603            )])
1604            .unwrap();
1605        assert_eq!(result.len(), 2);
1606        assert!(result.iter().all(|u| u.id != 1));
1607    }
1608
1609    #[test]
1610    fn test_repo_find_by_between() {
1611        let repo = InMemoryRepository::from_vec(vec![
1612            User::new(1, "Alice", 30, "a@b.com"),
1613            User::new(2, "Bob", 25, "b@b.com"),
1614            User::new(3, "Carol", 35, "c@b.com"),
1615            User::new(4, "Dave", 22, "d@b.com"),
1616        ]);
1617
1618        let result = repo
1619            .find_by(&[WhereCondition::between(
1620                "age",
1621                Value::I64(25),
1622                Value::I64(35),
1623            )])
1624            .unwrap();
1625        assert_eq!(result.len(), 3);
1626    }
1627
1628    #[test]
1629    fn test_repo_find_by_multiple_conditions() {
1630        let repo = InMemoryRepository::from_vec(vec![
1631            User::new(1, "Alice", 30, "a@b.com"),
1632            User::new(2, "Bob", 30, "b@b.com"),
1633            User::new(3, "Alice", 25, "c@b.com"),
1634        ]);
1635
1636        let result = repo
1637            .find_by(&[
1638                WhereCondition::new("name", WhereOp::Eq, Value::String("Alice".to_string())),
1639                WhereCondition::new("age", WhereOp::Ge, Value::I64(30)),
1640            ])
1641            .unwrap();
1642        assert_eq!(result.len(), 1);
1643        assert_eq!(result[0].id, 1);
1644    }
1645
1646    #[test]
1647    fn test_repo_find_one_by() {
1648        let repo = InMemoryRepository::from_vec(vec![
1649            User::new(1, "Alice", 30, "a@b.com"),
1650            User::new(2, "Bob", 25, "b@b.com"),
1651        ]);
1652
1653        let result = repo
1654            .find_one_by(&[WhereCondition::new(
1655                "name",
1656                WhereOp::Eq,
1657                Value::String("Bob".to_string()),
1658            )])
1659            .unwrap();
1660        assert!(result.is_some());
1661        assert_eq!(result.unwrap().id, 2);
1662    }
1663
1664    #[test]
1665    fn test_repo_find_one_by_missing() {
1666        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1667
1668        let result = repo
1669            .find_one_by(&[WhereCondition::new(
1670                "name",
1671                WhereOp::Eq,
1672                Value::String("Missing".to_string()),
1673            )])
1674            .unwrap();
1675        assert!(result.is_none());
1676    }
1677
1678    #[test]
1679    fn test_repo_count_by() {
1680        let repo = InMemoryRepository::from_vec(vec![
1681            User::new(1, "Alice", 30, "a@b.com"),
1682            User::new(2, "Bob", 30, "b@b.com"),
1683            User::new(3, "Carol", 25, "c@b.com"),
1684        ]);
1685
1686        let count = repo
1687            .count_by(&[WhereCondition::new("age", WhereOp::Eq, Value::I64(30))])
1688            .unwrap();
1689        assert_eq!(count, 2);
1690    }
1691
1692    #[test]
1693    fn test_repo_delete_by() {
1694        let repo = InMemoryRepository::from_vec(vec![
1695            User::new(1, "Alice", 30, "a@b.com"),
1696            User::new(2, "Bob", 30, "b@b.com"),
1697            User::new(3, "Carol", 25, "c@b.com"),
1698        ]);
1699
1700        let deleted = repo
1701            .delete_by(&[WhereCondition::new("age", WhereOp::Eq, Value::I64(30))])
1702            .unwrap();
1703        assert_eq!(deleted, 2);
1704        assert_eq!(repo.len(), 1);
1705    }
1706
1707    // ===== 分页 =====
1708
1709    #[test]
1710    fn test_repo_paginate() {
1711        let users: Vec<User> = (1..=25)
1712            .map(|i| User::new(i, &format!("User{}", i), 20 + (i % 30), "u@b.com"))
1713            .collect();
1714        let repo = InMemoryRepository::from_vec(users);
1715
1716        let page = repo.paginate(1, 10).unwrap();
1717        assert_eq!(page.page, 1);
1718        assert_eq!(page.page_size, 10);
1719        assert_eq!(page.total, 25);
1720        assert_eq!(page.total_pages(), 3);
1721        assert_eq!(page.items.len(), 10);
1722        assert!(page.has_next());
1723        assert!(!page.has_prev());
1724    }
1725
1726    #[test]
1727    fn test_repo_paginate_last_page() {
1728        let users: Vec<User> = (1..=25)
1729            .map(|i| User::new(i, &format!("User{}", i), 20, "u@b.com"))
1730            .collect();
1731        let repo = InMemoryRepository::from_vec(users);
1732
1733        let page = repo.paginate(3, 10).unwrap();
1734        assert_eq!(page.items.len(), 5);
1735        assert!(page.has_prev());
1736        assert!(!page.has_next());
1737    }
1738
1739    #[test]
1740    fn test_repo_paginate_out_of_range() {
1741        let users: Vec<User> = (1..=5)
1742            .map(|i| User::new(i, &format!("User{}", i), 20, "u@b.com"))
1743            .collect();
1744        let repo = InMemoryRepository::from_vec(users);
1745
1746        let page = repo.paginate(10, 10).unwrap();
1747        assert_eq!(page.items.len(), 0);
1748        assert_eq!(page.total, 5);
1749    }
1750
1751    #[test]
1752    fn test_repo_paginate_by() {
1753        let users: Vec<User> = (1..=20)
1754            .map(|i| User::new(i, &format!("User{}", i), 20 + (i % 5), "u@b.com"))
1755            .collect();
1756        let repo = InMemoryRepository::from_vec(users);
1757
1758        // age=22 的用户:i=2,7,12,17 → 4 个
1759        let page = repo
1760            .paginate_by(
1761                &[WhereCondition::new("age", WhereOp::Eq, Value::I64(22))],
1762                1,
1763                2,
1764            )
1765            .unwrap();
1766        assert_eq!(page.total, 4);
1767        assert_eq!(page.items.len(), 2);
1768        assert_eq!(page.total_pages(), 2);
1769    }
1770
1771    // ===== GenericKeyRepository =====
1772
1773    #[test]
1774    fn test_generic_key_repo_basic() {
1775        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::new();
1776        assert!(repo.is_empty());
1777
1778        let user = User::new(1, "Alice", 30, "a@b.com");
1779        repo.save(user.clone()).unwrap();
1780        assert_eq!(repo.len(), 1);
1781
1782        let found = repo.find_by_id(&1).unwrap();
1783        assert_eq!(found, Some(user));
1784    }
1785
1786    #[test]
1787    fn test_generic_key_repo_delete() {
1788        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::from_vec(vec![
1789            User::new(1, "Alice", 30, "a@b.com"),
1790            User::new(2, "Bob", 25, "b@b.com"),
1791        ]);
1792
1793        let deleted = repo.delete(&1).unwrap();
1794        assert_eq!(deleted, 1);
1795        assert_eq!(repo.len(), 1);
1796
1797        let remaining = repo.find_all().unwrap();
1798        assert_eq!(remaining[0].id, 2);
1799    }
1800
1801    #[test]
1802    fn test_generic_key_repo_find_by() {
1803        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::from_vec(vec![
1804            User::new(1, "Alice", 30, "a@b.com"),
1805            User::new(2, "Bob", 30, "b@b.com"),
1806            User::new(3, "Carol", 25, "c@b.com"),
1807        ]);
1808
1809        let result = repo
1810            .find_by(&[WhereCondition::new("age", WhereOp::Eq, Value::I64(30))])
1811            .unwrap();
1812        assert_eq!(result.len(), 2);
1813    }
1814
1815    #[test]
1816    fn test_generic_key_repo_paginate() {
1817        let users: Vec<User> = (1..=15)
1818            .map(|i| User::new(i, &format!("User{}", i), 20, "u@b.com"))
1819            .collect();
1820        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::from_vec(users);
1821
1822        let page = repo.paginate(2, 10).unwrap();
1823        assert_eq!(page.items.len(), 5);
1824        assert_eq!(page.total, 15);
1825        assert_eq!(page.page, 2);
1826    }
1827
1828    #[test]
1829    fn test_generic_key_repo_count() {
1830        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::from_vec(vec![
1831            User::new(1, "Alice", 30, "a@b.com"),
1832            User::new(2, "Bob", 25, "b@b.com"),
1833        ]);
1834        assert_eq!(repo.count().unwrap(), 2);
1835    }
1836
1837    #[test]
1838    fn test_generic_key_repo_exists() {
1839        let repo: GenericKeyRepository<User, i64> =
1840            GenericKeyRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1841        assert!(repo.exists(&1).unwrap());
1842        assert!(!repo.exists(&999).unwrap());
1843    }
1844
1845    // ===== simple_regex =====
1846
1847    #[test]
1848    fn test_simple_regex_literal() {
1849        let re = simple_regex::compile("^abc$").unwrap();
1850        assert!(re.is_match("abc"));
1851        assert!(!re.is_match("abcd"));
1852    }
1853
1854    #[test]
1855    fn test_simple_regex_wildcard() {
1856        let re = simple_regex::compile("^Ali.*$").unwrap();
1857        assert!(re.is_match("Alice"));
1858        assert!(re.is_match("Alicia"));
1859        assert!(!re.is_match("Bob"));
1860    }
1861
1862    #[test]
1863    fn test_simple_regex_no_anchors() {
1864        let re = simple_regex::compile("ab").unwrap();
1865        assert!(re.is_match("ab"));
1866    }
1867
1868    // ===== 端到端场景 =====
1869
1870    #[test]
1871    fn test_e2e_repository_workflow() {
1872        let repo = InMemoryRepository::<User>::new();
1873
1874        // 1. 批量插入
1875        let users = vec![
1876            User::new(1, "Alice", 30, "alice@example.com"),
1877            User::new(2, "Bob", 25, "bob@example.com"),
1878            User::new(3, "Carol", 35, "carol@example.com"),
1879            User::new(4, "Dave", 28, "dave@example.com"),
1880            User::new(5, "Eve", 32, "eve@example.com"),
1881        ];
1882        repo.save_many(users).unwrap();
1883        assert_eq!(repo.count().unwrap(), 5);
1884
1885        // 2. 查找成年人(age >= 30)
1886        let adults = repo
1887            .find_by(&[WhereCondition::new("age", WhereOp::Ge, Value::I64(30))])
1888            .unwrap();
1889        assert_eq!(adults.len(), 3);
1890
1891        // 3. 分页查询
1892        let page1 = repo.paginate(1, 2).unwrap();
1893        assert_eq!(page1.items.len(), 2);
1894        assert_eq!(page1.total_pages(), 3);
1895
1896        let page2 = repo.paginate(2, 2).unwrap();
1897        assert_eq!(page2.items.len(), 2);
1898
1899        let page3 = repo.paginate(3, 2).unwrap();
1900        assert_eq!(page3.items.len(), 1);
1901
1902        // 4. 条件分页查询(age >= 30)
1903        let adult_page = repo
1904            .paginate_by(
1905                &[WhereCondition::new("age", WhereOp::Ge, Value::I64(30))],
1906                1,
1907                2,
1908            )
1909            .unwrap();
1910        assert_eq!(adult_page.total, 3);
1911        assert_eq!(adult_page.items.len(), 2);
1912
1913        // 5. 更新
1914        repo.save(User::new(1, "Alice Smith", 31, "alice.smith@example.com"))
1915            .unwrap();
1916        let updated = repo.find_by_id(&Value::I64(1)).unwrap().unwrap();
1917        assert_eq!(updated.name, "Alice Smith");
1918        assert_eq!(updated.age, 31);
1919
1920        // 6. 删除
1921        let deleted = repo.delete(&Value::I64(2)).unwrap();
1922        assert_eq!(deleted, 1);
1923        assert_eq!(repo.count().unwrap(), 4);
1924        assert!(!repo.exists(&Value::I64(2)).unwrap());
1925
1926        // 7. 条件删除 age >= 31:Alice(31) + Carol(35) + Eve(32) = 3 个
1927        let deleted_by = repo
1928            .delete_by(&[WhereCondition::new("age", WhereOp::Ge, Value::I64(31))])
1929            .unwrap();
1930        assert_eq!(deleted_by, 3);
1931        assert_eq!(repo.count().unwrap(), 1); // 仅剩 Dave(28)
1932    }
1933
1934    #[test]
1935    fn test_e2e_pagination_navigation() {
1936        let users: Vec<User> = (1..=100)
1937            .map(|i| User::new(i, &format!("User{}", i), 20, "u@b.com"))
1938            .collect();
1939        let repo = InMemoryRepository::from_vec(users);
1940
1941        let mut current_page = 1u64;
1942        let mut visited: Vec<u64> = Vec::new();
1943        loop {
1944            let page = repo.paginate(current_page, 10).unwrap();
1945            visited.push(current_page);
1946            if !page.has_next() {
1947                break;
1948            }
1949            current_page += 1;
1950        }
1951        assert_eq!(visited.len(), 10);
1952        assert_eq!(visited, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
1953    }
1954}