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,集成测试用 SqlRepository
26//! 4. **统一 API**:CRUD + 分页 + 条件查询接口统一
27//!
28//! # 使用示例
29//!
30//! ```
31//! use sz_orm_core::repository::{
32//!     InMemoryRepository, Repository, WhereCondition, WhereOp, PageResult,
33//! };
34//! use sz_orm_core::Value;
35//! use std::collections::HashMap;
36//!
37//! // 假设 User 是 Model 的实现
38//! // let repo = InMemoryRepository::<User>::new();
39//! // let user = repo.find_by_id(1)?;
40//! // let adults = repo.find_by(&[WhereCondition::new("age", WhereOp::Ge, Value::I64(18))])?;
41//! ```
42
43use crate::value::Value;
44use std::fmt::Debug;
45use std::sync::RwLock;
46
47// ============================================================================
48// WhereCondition — 查询条件
49// ============================================================================
50
51/// 查询操作符
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub enum WhereOp {
54    /// `=`
55    Eq,
56    /// `!=`
57    Ne,
58    /// `>`
59    Gt,
60    /// `>=`
61    Ge,
62    /// `<`
63    Lt,
64    /// `<=`
65    Le,
66    /// `LIKE`
67    Like,
68    /// `IN`
69    In,
70    /// `NOT IN`
71    NotIn,
72    /// `IS NULL`
73    IsNull,
74    /// `IS NOT NULL`
75    IsNotNull,
76    /// `BETWEEN`
77    Between,
78}
79
80impl WhereOp {
81    /// 操作符名称
82    pub fn name(&self) -> &'static str {
83        match self {
84            WhereOp::Eq => "eq",
85            WhereOp::Ne => "ne",
86            WhereOp::Gt => "gt",
87            WhereOp::Ge => "ge",
88            WhereOp::Lt => "lt",
89            WhereOp::Le => "le",
90            WhereOp::Like => "like",
91            WhereOp::In => "in",
92            WhereOp::NotIn => "not_in",
93            WhereOp::IsNull => "is_null",
94            WhereOp::IsNotNull => "is_not_null",
95            WhereOp::Between => "between",
96        }
97    }
98}
99
100/// 查询条件
101#[derive(Debug, Clone)]
102pub struct WhereCondition {
103    pub field: String,
104    pub op: WhereOp,
105    pub value: Value,
106    /// For Between / In / NotIn,副值列表
107    pub extra_values: Vec<Value>,
108}
109
110impl WhereCondition {
111    /// 创建单值条件(Eq/Ne/Gt/Ge/Lt/Le/Like)
112    pub fn new(field: impl Into<String>, op: WhereOp, value: Value) -> Self {
113        Self {
114            field: field.into(),
115            op,
116            value,
117            extra_values: Vec::new(),
118        }
119    }
120
121    /// 创建 IsNull / IsNotNull 条件
122    pub fn null_check(field: impl Into<String>, op: WhereOp) -> Self {
123        Self {
124            field: field.into(),
125            op,
126            value: Value::Null,
127            extra_values: Vec::new(),
128        }
129    }
130
131    /// 创建 In / NotIn 条件
132    pub fn in_op(field: impl Into<String>, op: WhereOp, values: Vec<Value>) -> Self {
133        Self {
134            field: field.into(),
135            op,
136            value: Value::Null,
137            extra_values: values,
138        }
139    }
140
141    /// 创建 Between 条件
142    pub fn between(field: impl Into<String>, low: Value, high: Value) -> Self {
143        Self {
144            field: field.into(),
145            op: WhereOp::Between,
146            value: low,
147            extra_values: vec![high],
148        }
149    }
150}
151
152// ============================================================================
153// PageResult — 分页结果
154// ============================================================================
155
156/// 分页结果
157#[derive(Debug, Clone)]
158pub struct PageResult<T> {
159    pub items: Vec<T>,
160    pub total: u64,
161    pub page: u64,
162    pub page_size: u64,
163}
164
165impl<T> PageResult<T> {
166    /// 创建分页结果
167    pub fn new(items: Vec<T>, total: u64, page: u64, page_size: u64) -> Self {
168        Self {
169            items,
170            total,
171            page,
172            page_size,
173        }
174    }
175
176    /// 总页数
177    pub fn total_pages(&self) -> u64 {
178        if self.page_size == 0 {
179            return 0;
180        }
181        self.total.div_ceil(self.page_size)
182    }
183
184    /// 是否有下一页
185    pub fn has_next(&self) -> bool {
186        self.page < self.total_pages()
187    }
188
189    /// 是否有上一页
190    pub fn has_prev(&self) -> bool {
191        self.page > 1
192    }
193
194    /// 是否为空
195    pub fn is_empty(&self) -> bool {
196        self.items.is_empty()
197    }
198
199    /// 当前页条数
200    pub fn len(&self) -> usize {
201        self.items.len()
202    }
203
204    /// 映射为其他类型
205    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> PageResult<U> {
206        PageResult {
207            items: self.items.into_iter().map(f).collect(),
208            total: self.total,
209            page: self.page,
210            page_size: self.page_size,
211        }
212    }
213}
214
215// ============================================================================
216// RepositoryError — 错误类型
217// ============================================================================
218
219/// Repository 错误
220#[derive(Debug, Clone, PartialEq)]
221pub enum RepositoryError {
222    /// 实体未找到
223    NotFound,
224    /// 数据库错误
225    DatabaseError(String),
226    /// 实体无效(如缺主键)
227    InvalidEntity(String),
228    /// 其他错误
229    Other(String),
230}
231
232impl std::fmt::Display for RepositoryError {
233    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
234        match self {
235            RepositoryError::NotFound => write!(f, "entity not found"),
236            RepositoryError::DatabaseError(msg) => write!(f, "database error: {}", msg),
237            RepositoryError::InvalidEntity(msg) => write!(f, "invalid entity: {}", msg),
238            RepositoryError::Other(msg) => write!(f, "repository error: {}", msg),
239        }
240    }
241}
242
243impl std::error::Error for RepositoryError {}
244
245/// Repository 结果类型
246pub type RepositoryResult<T> = Result<T, RepositoryError>;
247
248// ============================================================================
249// Repository trait — 仓储接口
250// ============================================================================
251
252/// 仓储接口(generic over Model-like entity E, primary key K)
253///
254/// E 不必是 `Model` trait 实现,仅需满足存储基本要求。
255/// 这样设计允许存储任意结构(DTO、聚合、领域实体等)。
256pub trait Repository<E>: Send + Sync {
257    /// 主键类型
258    type Key: Clone + Debug + PartialEq + Send + Sync;
259
260    /// 提取实体的主键
261    fn key_of(&self, entity: &E) -> Self::Key;
262
263    /// 按主键查找
264    fn find_by_id(&self, key: &Self::Key) -> RepositoryResult<Option<E>>;
265
266    /// 查询所有
267    fn find_all(&self) -> RepositoryResult<Vec<E>>;
268
269    /// 按条件查询
270    fn find_by(&self, conditions: &[WhereCondition]) -> RepositoryResult<Vec<E>>;
271
272    /// 按条件查询单条
273    fn find_one_by(&self, conditions: &[WhereCondition]) -> RepositoryResult<Option<E>> {
274        let mut items = self.find_by(conditions)?;
275        if items.is_empty() {
276            Ok(None)
277        } else {
278            Ok(Some(items.remove(0)))
279        }
280    }
281
282    /// 保存(INSERT 或 UPDATE)
283    ///
284    /// 返回保存后的实体(可能是克隆,主键可能被填充)
285    fn save(&self, entity: E) -> RepositoryResult<E>;
286
287    /// 批量保存
288    fn save_many(&self, entities: Vec<E>) -> RepositoryResult<Vec<E>> {
289        let mut saved = Vec::with_capacity(entities.len());
290        for e in entities {
291            saved.push(self.save(e)?);
292        }
293        Ok(saved)
294    }
295
296    /// 按主键删除
297    fn delete(&self, key: &Self::Key) -> RepositoryResult<usize>;
298
299    /// 按条件删除
300    fn delete_by(&self, conditions: &[WhereCondition]) -> RepositoryResult<usize> {
301        let items = self.find_by(conditions)?;
302        let mut count = 0;
303        for item in items {
304            let key = self.key_of(&item);
305            count += self.delete(&key)?;
306        }
307        Ok(count)
308    }
309
310    /// 总数
311    fn count(&self) -> RepositoryResult<u64>;
312
313    /// 按条件计数
314    fn count_by(&self, conditions: &[WhereCondition]) -> RepositoryResult<u64> {
315        let items = self.find_by(conditions)?;
316        Ok(items.len() as u64)
317    }
318
319    /// 主键是否存在
320    fn exists(&self, key: &Self::Key) -> RepositoryResult<bool> {
321        Ok(self.find_by_id(key)?.is_some())
322    }
323
324    /// 分页查询
325    fn paginate(&self, page: u64, page_size: u64) -> RepositoryResult<PageResult<E>>
326    where
327        E: Clone,
328    {
329        let all = self.find_all()?;
330        let total = all.len() as u64;
331        let start = ((page.saturating_sub(1)) * page_size) as usize;
332        let end = (start + page_size as usize).min(all.len());
333
334        let items = if start < all.len() {
335            all[start..end].to_vec()
336        } else {
337            Vec::new()
338        };
339
340        Ok(PageResult::new(items, total, page, page_size))
341    }
342
343    /// 按条件分页查询
344    fn paginate_by(
345        &self,
346        conditions: &[WhereCondition],
347        page: u64,
348        page_size: u64,
349    ) -> RepositoryResult<PageResult<E>>
350    where
351        E: Clone,
352    {
353        let all = self.find_by(conditions)?;
354        let total = all.len() as u64;
355        let start = ((page.saturating_sub(1)) * page_size) as usize;
356        let end = (start + page_size as usize).min(all.len());
357
358        let items = if start < all.len() {
359            all[start..end].to_vec()
360        } else {
361            Vec::new()
362        };
363
364        Ok(PageResult::new(items, total, page, page_size))
365    }
366}
367
368// ============================================================================
369// InMemoryRepository — 内存仓储实现
370// ============================================================================
371
372/// 内存仓储实现
373///
374/// 使用 `Vec<E>` 存储实体,主键通过 `key_of` 提取。
375/// 适合单元测试、原型开发、无数据库场景。
376pub struct InMemoryRepository<E: Clone + Send + Sync + 'static> {
377    storage: RwLock<Vec<E>>,
378}
379
380impl<E: Clone + Send + Sync + 'static> InMemoryRepository<E> {
381    /// 创建空仓储
382    pub fn new() -> Self {
383        Self {
384            storage: RwLock::new(Vec::new()),
385        }
386    }
387
388    /// 从已有集合创建
389    pub fn from_vec(items: Vec<E>) -> Self {
390        Self {
391            storage: RwLock::new(items),
392        }
393    }
394
395    /// 当前存储条数
396    pub fn len(&self) -> usize {
397        let storage = self
398            .storage
399            .read()
400            .expect("InMemoryRepository storage lock poisoned (len)");
401        storage.len()
402    }
403
404    /// 是否为空
405    pub fn is_empty(&self) -> bool {
406        self.len() == 0
407    }
408
409    /// 清空
410    pub fn clear(&self) {
411        let mut storage = self
412            .storage
413            .write()
414            .expect("InMemoryRepository storage lock poisoned (clear)");
415        storage.clear();
416    }
417}
418
419impl<E: Clone + Send + Sync + 'static> Default for InMemoryRepository<E> {
420    fn default() -> Self {
421        Self::new()
422    }
423}
424
425/// 值比较辅助函数(支持基本类型 + Value 比较)
426fn value_matches(value: &Value, op: WhereOp, target: &Value, extras: &[Value]) -> bool {
427    use Value::*;
428    match op {
429        WhereOp::Eq => value == target,
430        WhereOp::Ne => value != target,
431        WhereOp::Gt => match (value, target) {
432            (I64(a), I64(b)) => a > b,
433            (F64(a), F64(b)) => a > b,
434            (F64(a), I64(b)) => a > &(*b as f64),
435            (I64(a), F64(b)) => a > &(*b as i64),
436            (String(a), String(b)) => a > b,
437            _ => false,
438        },
439        WhereOp::Ge => match (value, target) {
440            (I64(a), I64(b)) => a >= b,
441            (F64(a), F64(b)) => a >= b,
442            (String(a), String(b)) => a >= b,
443            _ => false,
444        },
445        WhereOp::Lt => match (value, target) {
446            (I64(a), I64(b)) => a < b,
447            (F64(a), F64(b)) => a < b,
448            (String(a), String(b)) => a < b,
449            _ => false,
450        },
451        WhereOp::Le => match (value, target) {
452            (I64(a), I64(b)) => a <= b,
453            (F64(a), F64(b)) => a <= b,
454            (String(a), String(b)) => a <= b,
455            _ => false,
456        },
457        WhereOp::Like => match (value, target) {
458            (String(a), String(b)) => {
459                // 简化 LIKE:将 % 转换为 .*,其他字符转义
460                let pattern = b.replace('%', ".*").replace('_', ".");
461                let full_pattern = format!("^{}$", pattern);
462                if let Ok(re) = simple_regex::compile(&full_pattern) {
463                    re.is_match(a)
464                } else {
465                    false
466                }
467            }
468            _ => false,
469        },
470        WhereOp::In => extras.iter().any(|v| v == value),
471        WhereOp::NotIn => !extras.iter().any(|v| v == value),
472        WhereOp::IsNull => matches!(value, Null),
473        WhereOp::IsNotNull => !matches!(value, Null),
474        WhereOp::Between => {
475            if extras.is_empty() {
476                return false;
477            }
478            let low = target;
479            let high = &extras[0];
480            // value >= low AND value <= high
481            value_matches(value, WhereOp::Ge, low, &[])
482                && value_matches(value, WhereOp::Le, high, &[])
483        }
484    }
485}
486
487/// 实体属性提取 trait(用户为实体实现此 trait 以支持 find_by)
488pub trait EntityAttributes: Send + Sync {
489    /// 按字段名获取属性值
490    fn get_attribute(&self, field: &str) -> Option<Value>;
491}
492
493/// InMemoryRepository 的 EntityAttributes-based 实现
494impl<E: Clone + Send + Sync + 'static + EntityAttributes> Repository<E> for InMemoryRepository<E> {
495    type Key = Value;
496
497    fn key_of(&self, entity: &E) -> Self::Key {
498        entity.get_attribute("id").unwrap_or(Value::Null)
499    }
500
501    fn find_by_id(&self, key: &Self::Key) -> RepositoryResult<Option<E>> {
502        let storage = self
503            .storage
504            .read()
505            .expect("InMemoryRepository storage lock poisoned (find_by_id)");
506        Ok(storage.iter().find(|e| self.key_of(e) == *key).cloned())
507    }
508
509    fn find_all(&self) -> RepositoryResult<Vec<E>> {
510        let storage = self
511            .storage
512            .read()
513            .expect("InMemoryRepository storage lock poisoned (find_all)");
514        Ok(storage.clone())
515    }
516
517    fn find_by(&self, conditions: &[WhereCondition]) -> RepositoryResult<Vec<E>> {
518        let storage = self
519            .storage
520            .read()
521            .expect("InMemoryRepository storage lock poisoned (find_by)");
522        let result: Vec<E> = storage
523            .iter()
524            .filter(|e| {
525                conditions.iter().all(|c| {
526                    let attr = e.get_attribute(&c.field);
527                    match (attr, c.op) {
528                        (None, WhereOp::IsNull) => true,
529                        (None, _) => false,
530                        (Some(v), _) => value_matches(&v, c.op, &c.value, &c.extra_values),
531                    }
532                })
533            })
534            .cloned()
535            .collect();
536        Ok(result)
537    }
538
539    fn save(&self, mut entity: E) -> RepositoryResult<E> {
540        let mut storage = self
541            .storage
542            .write()
543            .expect("InMemoryRepository storage lock poisoned (save)");
544        let key = self.key_of(&entity);
545
546        // 查找是否已存在
547        let existing_idx = storage.iter().position(|e| self.key_of(e) == key);
548
549        match existing_idx {
550            Some(idx) => {
551                storage[idx] = entity.clone();
552            }
553            None => {
554                storage.push(entity.clone());
555            }
556        }
557        // 注意:entity 可能被修改(如自增主键),这里返回原值
558        let _ = &mut entity; // 标记 mut 以符合签名
559        Ok(entity)
560    }
561
562    fn delete(&self, key: &Self::Key) -> RepositoryResult<usize> {
563        let mut storage = self
564            .storage
565            .write()
566            .expect("InMemoryRepository storage lock poisoned (delete)");
567        let before = storage.len();
568        storage.retain(|e| self.key_of(e) != *key);
569        Ok(before - storage.len())
570    }
571
572    fn count(&self) -> RepositoryResult<u64> {
573        Ok(self.len() as u64)
574    }
575}
576
577// ============================================================================
578// simple_regex — 极简 LIKE 模式匹配(避免引入正则依赖)
579// ============================================================================
580
581mod simple_regex {
582    /// 极简正则编译器:仅支持 `.*`、`^`、`$`、字面字符
583    pub struct Regex {
584        patterns: Vec<Pattern>,
585    }
586
587    enum Pattern {
588        AnyChars,      // .*(贪婪匹配任意字符)
589        Literal(char), // 字面字符
590        Start,         // ^
591        End,           // $
592    }
593
594    pub fn compile(pattern: &str) -> Result<Regex, String> {
595        let mut patterns = Vec::new();
596        let chars: Vec<char> = pattern.chars().collect();
597        let mut i = 0;
598        while i < chars.len() {
599            match chars[i] {
600                '^' => {
601                    patterns.push(Pattern::Start);
602                    i += 1;
603                }
604                '$' => {
605                    patterns.push(Pattern::End);
606                    i += 1;
607                }
608                '.' if i + 1 < chars.len() && chars[i + 1] == '*' => {
609                    patterns.push(Pattern::AnyChars);
610                    i += 2;
611                }
612                c => {
613                    patterns.push(Pattern::Literal(c));
614                    i += 1;
615                }
616            }
617        }
618        Ok(Regex { patterns })
619    }
620
621    impl Regex {
622        pub fn is_match(&self, text: &str) -> bool {
623            self.match_from(text, 0, 0)
624        }
625
626        fn match_from(&self, text: &str, text_idx: usize, pat_idx: usize) -> bool {
627            let chars: Vec<char> = text.chars().collect();
628            if pat_idx >= self.patterns.len() {
629                return text_idx == chars.len();
630            }
631            match &self.patterns[pat_idx] {
632                Pattern::Start => self.match_from(text, 0, pat_idx + 1),
633                Pattern::End => text_idx == chars.len(),
634                Pattern::Literal(c) => {
635                    if text_idx < chars.len() && chars[text_idx] == *c {
636                        self.match_from(text, text_idx + 1, pat_idx + 1)
637                    } else {
638                        false
639                    }
640                }
641                Pattern::AnyChars => {
642                    // 尝试匹配 0 到 len 个字符
643                    for skip in 0..=(chars.len() - text_idx) {
644                        if self.match_from(text, text_idx + skip, pat_idx + 1) {
645                            return true;
646                        }
647                    }
648                    false
649                }
650            }
651        }
652    }
653}
654
655// ============================================================================
656// GenericKeyRepository — 支持任意 Key 类型的内存仓储
657// ============================================================================
658
659/// 通用 Key 提取 trait(用户为实体实现此 trait 以支持任意 Key 类型)
660pub trait EntityKey<K>: Send + Sync {
661    /// 提取主键
662    fn key(&self) -> K;
663}
664
665/// 通用 Key 内存仓储
666pub struct GenericKeyRepository<E, K>
667where
668    E: Clone + Send + Sync + 'static,
669    K: Clone + Debug + PartialEq + Send + Sync + 'static,
670{
671    storage: RwLock<Vec<E>>,
672    _phantom: std::marker::PhantomData<K>,
673}
674
675impl<E, K> GenericKeyRepository<E, K>
676where
677    E: Clone + Send + Sync + 'static,
678    K: Clone + Debug + PartialEq + Send + Sync + 'static,
679{
680    pub fn new() -> Self {
681        Self {
682            storage: RwLock::new(Vec::new()),
683            _phantom: std::marker::PhantomData,
684        }
685    }
686
687    pub fn from_vec(items: Vec<E>) -> Self {
688        Self {
689            storage: RwLock::new(items),
690            _phantom: std::marker::PhantomData,
691        }
692    }
693
694    pub fn len(&self) -> usize {
695        self.storage
696            .read()
697            .expect("GenericKeyRepository storage lock poisoned (len)")
698            .len()
699    }
700
701    pub fn is_empty(&self) -> bool {
702        self.len() == 0
703    }
704
705    pub fn clear(&self) {
706        self.storage
707            .write()
708            .expect("GenericKeyRepository storage lock poisoned (clear)")
709            .clear();
710    }
711}
712
713impl<E, K> Default for GenericKeyRepository<E, K>
714where
715    E: Clone + Send + Sync + 'static,
716    K: Clone + Debug + PartialEq + Send + Sync + 'static,
717{
718    fn default() -> Self {
719        Self::new()
720    }
721}
722
723impl<E, K> Repository<E> for GenericKeyRepository<E, K>
724where
725    E: Clone + Send + Sync + 'static + EntityKey<K> + EntityAttributes,
726    K: Clone + Debug + PartialEq + Send + Sync + 'static,
727{
728    type Key = K;
729
730    fn key_of(&self, entity: &E) -> Self::Key {
731        entity.key()
732    }
733
734    fn find_by_id(&self, key: &Self::Key) -> RepositoryResult<Option<E>> {
735        let storage = self
736            .storage
737            .read()
738            .expect("GenericKeyRepository storage lock poisoned (find_by_id)");
739        Ok(storage.iter().find(|e| &e.key() == key).cloned())
740    }
741
742    fn find_all(&self) -> RepositoryResult<Vec<E>> {
743        Ok(self
744            .storage
745            .read()
746            .expect("GenericKeyRepository storage lock poisoned (find_all)")
747            .clone())
748    }
749
750    fn find_by(&self, conditions: &[WhereCondition]) -> RepositoryResult<Vec<E>> {
751        let storage = self
752            .storage
753            .read()
754            .expect("GenericKeyRepository storage lock poisoned (find_by)");
755        let result: Vec<E> = storage
756            .iter()
757            .filter(|e| {
758                conditions.iter().all(|c| {
759                    let attr = e.get_attribute(&c.field);
760                    match (attr, c.op) {
761                        (None, WhereOp::IsNull) => true,
762                        (None, _) => false,
763                        (Some(v), _) => value_matches(&v, c.op, &c.value, &c.extra_values),
764                    }
765                })
766            })
767            .cloned()
768            .collect();
769        Ok(result)
770    }
771
772    fn save(&self, entity: E) -> RepositoryResult<E> {
773        let mut storage = self
774            .storage
775            .write()
776            .expect("GenericKeyRepository storage lock poisoned (save)");
777        let key = entity.key();
778        let existing_idx = storage.iter().position(|e| e.key() == key);
779        match existing_idx {
780            Some(idx) => {
781                storage[idx] = entity.clone();
782            }
783            None => {
784                storage.push(entity.clone());
785            }
786        }
787        Ok(entity)
788    }
789
790    fn delete(&self, key: &Self::Key) -> RepositoryResult<usize> {
791        let mut storage = self
792            .storage
793            .write()
794            .expect("GenericKeyRepository storage lock poisoned (delete)");
795        let before = storage.len();
796        storage.retain(|e| &e.key() != key);
797        Ok(before - storage.len())
798    }
799
800    fn count(&self) -> RepositoryResult<u64> {
801        Ok(self.len() as u64)
802    }
803}
804
805// ============================================================================
806// 单元测试
807// ============================================================================
808
809#[cfg(test)]
810mod tests {
811    use super::*;
812
813    // ===== 测试用实体 =====
814
815    #[derive(Debug, Clone, PartialEq)]
816    struct User {
817        id: i64,
818        name: String,
819        age: i64,
820        email: String,
821    }
822
823    impl User {
824        fn new(id: i64, name: &str, age: i64, email: &str) -> Self {
825            Self {
826                id,
827                name: name.to_string(),
828                age,
829                email: email.to_string(),
830            }
831        }
832    }
833
834    impl EntityAttributes for User {
835        fn get_attribute(&self, field: &str) -> Option<Value> {
836            match field {
837                "id" => Some(Value::I64(self.id)),
838                "name" => Some(Value::String(self.name.clone())),
839                "age" => Some(Value::I64(self.age)),
840                "email" => Some(Value::String(self.email.clone())),
841                _ => None,
842            }
843        }
844    }
845
846    impl EntityKey<i64> for User {
847        fn key(&self) -> i64 {
848            self.id
849        }
850    }
851
852    // ===== WhereOp / WhereCondition =====
853
854    #[test]
855    fn test_where_op_name() {
856        assert_eq!(WhereOp::Eq.name(), "eq");
857        assert_eq!(WhereOp::Ne.name(), "ne");
858        assert_eq!(WhereOp::Gt.name(), "gt");
859        assert_eq!(WhereOp::Like.name(), "like");
860        assert_eq!(WhereOp::In.name(), "in");
861        assert_eq!(WhereOp::IsNull.name(), "is_null");
862        assert_eq!(WhereOp::Between.name(), "between");
863    }
864
865    #[test]
866    fn test_where_condition_new() {
867        let c = WhereCondition::new("age", WhereOp::Ge, Value::I64(18));
868        assert_eq!(c.field, "age");
869        assert_eq!(c.op, WhereOp::Ge);
870        assert_eq!(c.value, Value::I64(18));
871        assert!(c.extra_values.is_empty());
872    }
873
874    #[test]
875    fn test_where_condition_null_check() {
876        let c = WhereCondition::null_check("deleted_at", WhereOp::IsNull);
877        assert_eq!(c.field, "deleted_at");
878        assert_eq!(c.op, WhereOp::IsNull);
879        assert_eq!(c.value, Value::Null);
880    }
881
882    #[test]
883    fn test_where_condition_in() {
884        let c = WhereCondition::in_op(
885            "id",
886            WhereOp::In,
887            vec![Value::I64(1), Value::I64(2), Value::I64(3)],
888        );
889        assert_eq!(c.field, "id");
890        assert_eq!(c.op, WhereOp::In);
891        assert_eq!(c.extra_values.len(), 3);
892    }
893
894    #[test]
895    fn test_where_condition_between() {
896        let c = WhereCondition::between("age", Value::I64(18), Value::I64(30));
897        assert_eq!(c.field, "age");
898        assert_eq!(c.op, WhereOp::Between);
899        assert_eq!(c.value, Value::I64(18));
900        assert_eq!(c.extra_values, vec![Value::I64(30)]);
901    }
902
903    // ===== PageResult =====
904
905    #[test]
906    fn test_page_result_total_pages() {
907        let pr = PageResult::new(vec![1, 2, 3], 100, 1, 10);
908        assert_eq!(pr.total_pages(), 10);
909    }
910
911    #[test]
912    fn test_page_result_total_pages_with_remainder() {
913        let pr: PageResult<i32> = PageResult::new(vec![], 105, 1, 10);
914        assert_eq!(pr.total_pages(), 11);
915    }
916
917    #[test]
918    fn test_page_result_total_pages_zero_size() {
919        let pr: PageResult<i32> = PageResult::new(vec![], 100, 1, 0);
920        assert_eq!(pr.total_pages(), 0);
921    }
922
923    #[test]
924    fn test_page_result_has_next() {
925        let pr = PageResult::new(vec![1, 2, 3], 100, 1, 10);
926        assert!(pr.has_next());
927        assert!(!pr.has_prev());
928    }
929
930    #[test]
931    fn test_page_result_has_prev() {
932        let pr = PageResult::new(vec![1, 2, 3], 100, 5, 10);
933        assert!(pr.has_prev());
934        assert!(pr.has_next()); // page 5 < total_pages 10
935    }
936
937    #[test]
938    fn test_page_result_is_empty() {
939        let pr: PageResult<i32> = PageResult::new(vec![], 0, 1, 10);
940        assert!(pr.is_empty());
941        assert_eq!(pr.len(), 0);
942    }
943
944    #[test]
945    fn test_page_result_map() {
946        let pr = PageResult::new(vec![1, 2, 3], 100, 1, 10);
947        let mapped = pr.map(|x| x * 2);
948        assert_eq!(mapped.items, vec![2, 4, 6]);
949        assert_eq!(mapped.total, 100);
950    }
951
952    // ===== RepositoryError =====
953
954    #[test]
955    fn test_repository_error_display() {
956        let e = RepositoryError::NotFound;
957        assert_eq!(e.to_string(), "entity not found");
958
959        let e = RepositoryError::DatabaseError("conn refused".to_string());
960        assert_eq!(e.to_string(), "database error: conn refused");
961
962        let e = RepositoryError::InvalidEntity("missing id".to_string());
963        assert_eq!(e.to_string(), "invalid entity: missing id");
964
965        let e = RepositoryError::Other("custom".to_string());
966        assert_eq!(e.to_string(), "repository error: custom");
967    }
968
969    #[test]
970    fn test_repository_error_eq() {
971        assert_eq!(RepositoryError::NotFound, RepositoryError::NotFound);
972        assert_ne!(
973            RepositoryError::NotFound,
974            RepositoryError::Other("x".to_string())
975        );
976    }
977
978    // ===== InMemoryRepository 基础 =====
979
980    #[test]
981    fn test_inmemory_create_empty() {
982        let repo = InMemoryRepository::<User>::new();
983        assert!(repo.is_empty());
984        assert_eq!(repo.len(), 0);
985    }
986
987    #[test]
988    fn test_inmemory_from_vec() {
989        let repo = InMemoryRepository::from_vec(vec![
990            User::new(1, "Alice", 30, "alice@example.com"),
991            User::new(2, "Bob", 25, "bob@example.com"),
992        ]);
993        assert_eq!(repo.len(), 2);
994    }
995
996    #[test]
997    fn test_inmemory_clear() {
998        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
999        assert_eq!(repo.len(), 1);
1000        repo.clear();
1001        assert_eq!(repo.len(), 0);
1002    }
1003
1004    // ===== Repository trait CRUD =====
1005
1006    #[test]
1007    fn test_repo_save_and_find_by_id() {
1008        let repo = InMemoryRepository::<User>::new();
1009        let user = User::new(1, "Alice", 30, "alice@example.com");
1010        let saved = repo.save(user.clone()).unwrap();
1011        assert_eq!(saved, user);
1012
1013        let found = repo.find_by_id(&Value::I64(1)).unwrap();
1014        assert_eq!(found, Some(user));
1015    }
1016
1017    #[test]
1018    fn test_repo_find_by_id_missing() {
1019        let repo = InMemoryRepository::<User>::new();
1020        let found = repo.find_by_id(&Value::I64(999)).unwrap();
1021        assert_eq!(found, None);
1022    }
1023
1024    #[test]
1025    fn test_repo_save_many() {
1026        let repo = InMemoryRepository::<User>::new();
1027        let users = vec![
1028            User::new(1, "Alice", 30, "alice@example.com"),
1029            User::new(2, "Bob", 25, "bob@example.com"),
1030            User::new(3, "Carol", 28, "carol@example.com"),
1031        ];
1032        let saved = repo.save_many(users.clone()).unwrap();
1033        assert_eq!(saved.len(), 3);
1034        assert_eq!(repo.len(), 3);
1035    }
1036
1037    #[test]
1038    fn test_repo_save_update_existing() {
1039        let repo = InMemoryRepository::<User>::new();
1040        repo.save(User::new(1, "Alice", 30, "alice@example.com"))
1041            .unwrap();
1042
1043        // 更新
1044        repo.save(User::new(1, "Alice Updated", 31, "alice2@example.com"))
1045            .unwrap();
1046
1047        assert_eq!(repo.len(), 1);
1048        let found = repo.find_by_id(&Value::I64(1)).unwrap().unwrap();
1049        assert_eq!(found.name, "Alice Updated");
1050        assert_eq!(found.age, 31);
1051    }
1052
1053    #[test]
1054    fn test_repo_find_all() {
1055        let repo = InMemoryRepository::from_vec(vec![
1056            User::new(1, "Alice", 30, "a@b.com"),
1057            User::new(2, "Bob", 25, "b@b.com"),
1058        ]);
1059        let all = repo.find_all().unwrap();
1060        assert_eq!(all.len(), 2);
1061    }
1062
1063    #[test]
1064    fn test_repo_find_all_empty() {
1065        let repo = InMemoryRepository::<User>::new();
1066        let all = repo.find_all().unwrap();
1067        assert!(all.is_empty());
1068    }
1069
1070    #[test]
1071    fn test_repo_delete() {
1072        let repo = InMemoryRepository::from_vec(vec![
1073            User::new(1, "Alice", 30, "a@b.com"),
1074            User::new(2, "Bob", 25, "b@b.com"),
1075        ]);
1076        let deleted = repo.delete(&Value::I64(1)).unwrap();
1077        assert_eq!(deleted, 1);
1078        assert_eq!(repo.len(), 1);
1079    }
1080
1081    #[test]
1082    fn test_repo_delete_missing() {
1083        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1084        let deleted = repo.delete(&Value::I64(999)).unwrap();
1085        assert_eq!(deleted, 0);
1086        assert_eq!(repo.len(), 1);
1087    }
1088
1089    #[test]
1090    fn test_repo_count() {
1091        let repo = InMemoryRepository::from_vec(vec![
1092            User::new(1, "Alice", 30, "a@b.com"),
1093            User::new(2, "Bob", 25, "b@b.com"),
1094            User::new(3, "Carol", 28, "c@b.com"),
1095        ]);
1096        assert_eq!(repo.count().unwrap(), 3);
1097    }
1098
1099    #[test]
1100    fn test_repo_count_empty() {
1101        let repo = InMemoryRepository::<User>::new();
1102        assert_eq!(repo.count().unwrap(), 0);
1103    }
1104
1105    #[test]
1106    fn test_repo_exists() {
1107        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1108        assert!(repo.exists(&Value::I64(1)).unwrap());
1109        assert!(!repo.exists(&Value::I64(999)).unwrap());
1110    }
1111
1112    // ===== Repository 条件查询 =====
1113
1114    #[test]
1115    fn test_repo_find_by_eq() {
1116        let repo = InMemoryRepository::from_vec(vec![
1117            User::new(1, "Alice", 30, "a@b.com"),
1118            User::new(2, "Bob", 30, "b@b.com"),
1119            User::new(3, "Carol", 25, "c@b.com"),
1120        ]);
1121
1122        let result = repo
1123            .find_by(&[WhereCondition::new("age", WhereOp::Eq, Value::I64(30))])
1124            .unwrap();
1125        assert_eq!(result.len(), 2);
1126    }
1127
1128    #[test]
1129    fn test_repo_find_by_gt() {
1130        let repo = InMemoryRepository::from_vec(vec![
1131            User::new(1, "Alice", 30, "a@b.com"),
1132            User::new(2, "Bob", 25, "b@b.com"),
1133            User::new(3, "Carol", 35, "c@b.com"),
1134        ]);
1135
1136        let result = repo
1137            .find_by(&[WhereCondition::new("age", WhereOp::Gt, Value::I64(28))])
1138            .unwrap();
1139        assert_eq!(result.len(), 2);
1140    }
1141
1142    #[test]
1143    fn test_repo_find_by_like() {
1144        let repo = InMemoryRepository::from_vec(vec![
1145            User::new(1, "Alice", 30, "alice@example.com"),
1146            User::new(2, "Bob", 25, "bob@example.com"),
1147            User::new(3, "Alicia", 28, "alicia@test.com"),
1148        ]);
1149
1150        let result = repo
1151            .find_by(&[WhereCondition::new(
1152                "name",
1153                WhereOp::Like,
1154                Value::String("Ali%".to_string()),
1155            )])
1156            .unwrap();
1157        assert_eq!(result.len(), 2);
1158    }
1159
1160    #[test]
1161    fn test_repo_find_by_in() {
1162        let repo = InMemoryRepository::from_vec(vec![
1163            User::new(1, "Alice", 30, "a@b.com"),
1164            User::new(2, "Bob", 25, "b@b.com"),
1165            User::new(3, "Carol", 28, "c@b.com"),
1166            User::new(4, "Dave", 32, "d@b.com"),
1167        ]);
1168
1169        let result = repo
1170            .find_by(&[WhereCondition::in_op(
1171                "id",
1172                WhereOp::In,
1173                vec![Value::I64(1), Value::I64(3)],
1174            )])
1175            .unwrap();
1176        assert_eq!(result.len(), 2);
1177    }
1178
1179    #[test]
1180    fn test_repo_find_by_not_in() {
1181        let repo = InMemoryRepository::from_vec(vec![
1182            User::new(1, "Alice", 30, "a@b.com"),
1183            User::new(2, "Bob", 25, "b@b.com"),
1184            User::new(3, "Carol", 28, "c@b.com"),
1185        ]);
1186
1187        let result = repo
1188            .find_by(&[WhereCondition::in_op(
1189                "id",
1190                WhereOp::NotIn,
1191                vec![Value::I64(1)],
1192            )])
1193            .unwrap();
1194        assert_eq!(result.len(), 2);
1195        assert!(result.iter().all(|u| u.id != 1));
1196    }
1197
1198    #[test]
1199    fn test_repo_find_by_between() {
1200        let repo = InMemoryRepository::from_vec(vec![
1201            User::new(1, "Alice", 30, "a@b.com"),
1202            User::new(2, "Bob", 25, "b@b.com"),
1203            User::new(3, "Carol", 35, "c@b.com"),
1204            User::new(4, "Dave", 22, "d@b.com"),
1205        ]);
1206
1207        let result = repo
1208            .find_by(&[WhereCondition::between(
1209                "age",
1210                Value::I64(25),
1211                Value::I64(35),
1212            )])
1213            .unwrap();
1214        assert_eq!(result.len(), 3);
1215    }
1216
1217    #[test]
1218    fn test_repo_find_by_multiple_conditions() {
1219        let repo = InMemoryRepository::from_vec(vec![
1220            User::new(1, "Alice", 30, "a@b.com"),
1221            User::new(2, "Bob", 30, "b@b.com"),
1222            User::new(3, "Alice", 25, "c@b.com"),
1223        ]);
1224
1225        let result = repo
1226            .find_by(&[
1227                WhereCondition::new("name", WhereOp::Eq, Value::String("Alice".to_string())),
1228                WhereCondition::new("age", WhereOp::Ge, Value::I64(30)),
1229            ])
1230            .unwrap();
1231        assert_eq!(result.len(), 1);
1232        assert_eq!(result[0].id, 1);
1233    }
1234
1235    #[test]
1236    fn test_repo_find_one_by() {
1237        let repo = InMemoryRepository::from_vec(vec![
1238            User::new(1, "Alice", 30, "a@b.com"),
1239            User::new(2, "Bob", 25, "b@b.com"),
1240        ]);
1241
1242        let result = repo
1243            .find_one_by(&[WhereCondition::new(
1244                "name",
1245                WhereOp::Eq,
1246                Value::String("Bob".to_string()),
1247            )])
1248            .unwrap();
1249        assert!(result.is_some());
1250        assert_eq!(result.unwrap().id, 2);
1251    }
1252
1253    #[test]
1254    fn test_repo_find_one_by_missing() {
1255        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1256
1257        let result = repo
1258            .find_one_by(&[WhereCondition::new(
1259                "name",
1260                WhereOp::Eq,
1261                Value::String("Missing".to_string()),
1262            )])
1263            .unwrap();
1264        assert!(result.is_none());
1265    }
1266
1267    #[test]
1268    fn test_repo_count_by() {
1269        let repo = InMemoryRepository::from_vec(vec![
1270            User::new(1, "Alice", 30, "a@b.com"),
1271            User::new(2, "Bob", 30, "b@b.com"),
1272            User::new(3, "Carol", 25, "c@b.com"),
1273        ]);
1274
1275        let count = repo
1276            .count_by(&[WhereCondition::new("age", WhereOp::Eq, Value::I64(30))])
1277            .unwrap();
1278        assert_eq!(count, 2);
1279    }
1280
1281    #[test]
1282    fn test_repo_delete_by() {
1283        let repo = InMemoryRepository::from_vec(vec![
1284            User::new(1, "Alice", 30, "a@b.com"),
1285            User::new(2, "Bob", 30, "b@b.com"),
1286            User::new(3, "Carol", 25, "c@b.com"),
1287        ]);
1288
1289        let deleted = repo
1290            .delete_by(&[WhereCondition::new("age", WhereOp::Eq, Value::I64(30))])
1291            .unwrap();
1292        assert_eq!(deleted, 2);
1293        assert_eq!(repo.len(), 1);
1294    }
1295
1296    // ===== 分页 =====
1297
1298    #[test]
1299    fn test_repo_paginate() {
1300        let users: Vec<User> = (1..=25)
1301            .map(|i| User::new(i, &format!("User{}", i), 20 + (i % 30), "u@b.com"))
1302            .collect();
1303        let repo = InMemoryRepository::from_vec(users);
1304
1305        let page = repo.paginate(1, 10).unwrap();
1306        assert_eq!(page.page, 1);
1307        assert_eq!(page.page_size, 10);
1308        assert_eq!(page.total, 25);
1309        assert_eq!(page.total_pages(), 3);
1310        assert_eq!(page.items.len(), 10);
1311        assert!(page.has_next());
1312        assert!(!page.has_prev());
1313    }
1314
1315    #[test]
1316    fn test_repo_paginate_last_page() {
1317        let users: Vec<User> = (1..=25)
1318            .map(|i| User::new(i, &format!("User{}", i), 20, "u@b.com"))
1319            .collect();
1320        let repo = InMemoryRepository::from_vec(users);
1321
1322        let page = repo.paginate(3, 10).unwrap();
1323        assert_eq!(page.items.len(), 5);
1324        assert!(page.has_prev());
1325        assert!(!page.has_next());
1326    }
1327
1328    #[test]
1329    fn test_repo_paginate_out_of_range() {
1330        let users: Vec<User> = (1..=5)
1331            .map(|i| User::new(i, &format!("User{}", i), 20, "u@b.com"))
1332            .collect();
1333        let repo = InMemoryRepository::from_vec(users);
1334
1335        let page = repo.paginate(10, 10).unwrap();
1336        assert_eq!(page.items.len(), 0);
1337        assert_eq!(page.total, 5);
1338    }
1339
1340    #[test]
1341    fn test_repo_paginate_by() {
1342        let users: Vec<User> = (1..=20)
1343            .map(|i| User::new(i, &format!("User{}", i), 20 + (i % 5), "u@b.com"))
1344            .collect();
1345        let repo = InMemoryRepository::from_vec(users);
1346
1347        // age=22 的用户:i=2,7,12,17 → 4 个
1348        let page = repo
1349            .paginate_by(
1350                &[WhereCondition::new("age", WhereOp::Eq, Value::I64(22))],
1351                1,
1352                2,
1353            )
1354            .unwrap();
1355        assert_eq!(page.total, 4);
1356        assert_eq!(page.items.len(), 2);
1357        assert_eq!(page.total_pages(), 2);
1358    }
1359
1360    // ===== GenericKeyRepository =====
1361
1362    #[test]
1363    fn test_generic_key_repo_basic() {
1364        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::new();
1365        assert!(repo.is_empty());
1366
1367        let user = User::new(1, "Alice", 30, "a@b.com");
1368        repo.save(user.clone()).unwrap();
1369        assert_eq!(repo.len(), 1);
1370
1371        let found = repo.find_by_id(&1).unwrap();
1372        assert_eq!(found, Some(user));
1373    }
1374
1375    #[test]
1376    fn test_generic_key_repo_delete() {
1377        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::from_vec(vec![
1378            User::new(1, "Alice", 30, "a@b.com"),
1379            User::new(2, "Bob", 25, "b@b.com"),
1380        ]);
1381
1382        let deleted = repo.delete(&1).unwrap();
1383        assert_eq!(deleted, 1);
1384        assert_eq!(repo.len(), 1);
1385
1386        let remaining = repo.find_all().unwrap();
1387        assert_eq!(remaining[0].id, 2);
1388    }
1389
1390    #[test]
1391    fn test_generic_key_repo_find_by() {
1392        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::from_vec(vec![
1393            User::new(1, "Alice", 30, "a@b.com"),
1394            User::new(2, "Bob", 30, "b@b.com"),
1395            User::new(3, "Carol", 25, "c@b.com"),
1396        ]);
1397
1398        let result = repo
1399            .find_by(&[WhereCondition::new("age", WhereOp::Eq, Value::I64(30))])
1400            .unwrap();
1401        assert_eq!(result.len(), 2);
1402    }
1403
1404    #[test]
1405    fn test_generic_key_repo_paginate() {
1406        let users: Vec<User> = (1..=15)
1407            .map(|i| User::new(i, &format!("User{}", i), 20, "u@b.com"))
1408            .collect();
1409        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::from_vec(users);
1410
1411        let page = repo.paginate(2, 10).unwrap();
1412        assert_eq!(page.items.len(), 5);
1413        assert_eq!(page.total, 15);
1414        assert_eq!(page.page, 2);
1415    }
1416
1417    #[test]
1418    fn test_generic_key_repo_count() {
1419        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::from_vec(vec![
1420            User::new(1, "Alice", 30, "a@b.com"),
1421            User::new(2, "Bob", 25, "b@b.com"),
1422        ]);
1423        assert_eq!(repo.count().unwrap(), 2);
1424    }
1425
1426    #[test]
1427    fn test_generic_key_repo_exists() {
1428        let repo: GenericKeyRepository<User, i64> =
1429            GenericKeyRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1430        assert!(repo.exists(&1).unwrap());
1431        assert!(!repo.exists(&999).unwrap());
1432    }
1433
1434    // ===== simple_regex =====
1435
1436    #[test]
1437    fn test_simple_regex_literal() {
1438        let re = simple_regex::compile("^abc$").unwrap();
1439        assert!(re.is_match("abc"));
1440        assert!(!re.is_match("abcd"));
1441    }
1442
1443    #[test]
1444    fn test_simple_regex_wildcard() {
1445        let re = simple_regex::compile("^Ali.*$").unwrap();
1446        assert!(re.is_match("Alice"));
1447        assert!(re.is_match("Alicia"));
1448        assert!(!re.is_match("Bob"));
1449    }
1450
1451    #[test]
1452    fn test_simple_regex_no_anchors() {
1453        let re = simple_regex::compile("ab").unwrap();
1454        assert!(re.is_match("ab"));
1455    }
1456
1457    // ===== 端到端场景 =====
1458
1459    #[test]
1460    fn test_e2e_repository_workflow() {
1461        let repo = InMemoryRepository::<User>::new();
1462
1463        // 1. 批量插入
1464        let users = vec![
1465            User::new(1, "Alice", 30, "alice@example.com"),
1466            User::new(2, "Bob", 25, "bob@example.com"),
1467            User::new(3, "Carol", 35, "carol@example.com"),
1468            User::new(4, "Dave", 28, "dave@example.com"),
1469            User::new(5, "Eve", 32, "eve@example.com"),
1470        ];
1471        repo.save_many(users).unwrap();
1472        assert_eq!(repo.count().unwrap(), 5);
1473
1474        // 2. 查找成年人(age >= 30)
1475        let adults = repo
1476            .find_by(&[WhereCondition::new("age", WhereOp::Ge, Value::I64(30))])
1477            .unwrap();
1478        assert_eq!(adults.len(), 3);
1479
1480        // 3. 分页查询
1481        let page1 = repo.paginate(1, 2).unwrap();
1482        assert_eq!(page1.items.len(), 2);
1483        assert_eq!(page1.total_pages(), 3);
1484
1485        let page2 = repo.paginate(2, 2).unwrap();
1486        assert_eq!(page2.items.len(), 2);
1487
1488        let page3 = repo.paginate(3, 2).unwrap();
1489        assert_eq!(page3.items.len(), 1);
1490
1491        // 4. 条件分页查询(age >= 30)
1492        let adult_page = repo
1493            .paginate_by(
1494                &[WhereCondition::new("age", WhereOp::Ge, Value::I64(30))],
1495                1,
1496                2,
1497            )
1498            .unwrap();
1499        assert_eq!(adult_page.total, 3);
1500        assert_eq!(adult_page.items.len(), 2);
1501
1502        // 5. 更新
1503        repo.save(User::new(1, "Alice Smith", 31, "alice.smith@example.com"))
1504            .unwrap();
1505        let updated = repo.find_by_id(&Value::I64(1)).unwrap().unwrap();
1506        assert_eq!(updated.name, "Alice Smith");
1507        assert_eq!(updated.age, 31);
1508
1509        // 6. 删除
1510        let deleted = repo.delete(&Value::I64(2)).unwrap();
1511        assert_eq!(deleted, 1);
1512        assert_eq!(repo.count().unwrap(), 4);
1513        assert!(!repo.exists(&Value::I64(2)).unwrap());
1514
1515        // 7. 条件删除 age >= 31:Alice(31) + Carol(35) + Eve(32) = 3 个
1516        let deleted_by = repo
1517            .delete_by(&[WhereCondition::new("age", WhereOp::Ge, Value::I64(31))])
1518            .unwrap();
1519        assert_eq!(deleted_by, 3);
1520        assert_eq!(repo.count().unwrap(), 1); // 仅剩 Dave(28)
1521    }
1522
1523    #[test]
1524    fn test_e2e_pagination_navigation() {
1525        let users: Vec<User> = (1..=100)
1526            .map(|i| User::new(i, &format!("User{}", i), 20, "u@b.com"))
1527            .collect();
1528        let repo = InMemoryRepository::from_vec(users);
1529
1530        let mut current_page = 1u64;
1531        let mut visited: Vec<u64> = Vec::new();
1532        loop {
1533            let page = repo.paginate(current_page, 10).unwrap();
1534            visited.push(current_page);
1535            if !page.has_next() {
1536                break;
1537            }
1538            current_page += 1;
1539        }
1540        assert_eq!(visited.len(), 10);
1541        assert_eq!(visited, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
1542    }
1543}