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.storage.read().unwrap();
398        storage.len()
399    }
400
401    /// 是否为空
402    pub fn is_empty(&self) -> bool {
403        self.len() == 0
404    }
405
406    /// 清空
407    pub fn clear(&self) {
408        let mut storage = self.storage.write().unwrap();
409        storage.clear();
410    }
411}
412
413impl<E: Clone + Send + Sync + 'static> Default for InMemoryRepository<E> {
414    fn default() -> Self {
415        Self::new()
416    }
417}
418
419/// 值比较辅助函数(支持基本类型 + Value 比较)
420fn value_matches(value: &Value, op: WhereOp, target: &Value, extras: &[Value]) -> bool {
421    use Value::*;
422    match op {
423        WhereOp::Eq => value == target,
424        WhereOp::Ne => value != target,
425        WhereOp::Gt => match (value, target) {
426            (I64(a), I64(b)) => a > b,
427            (F64(a), F64(b)) => a > b,
428            (F64(a), I64(b)) => a > &(*b as f64),
429            (I64(a), F64(b)) => a > &(*b as i64),
430            (String(a), String(b)) => a > b,
431            _ => false,
432        },
433        WhereOp::Ge => match (value, target) {
434            (I64(a), I64(b)) => a >= b,
435            (F64(a), F64(b)) => a >= b,
436            (String(a), String(b)) => a >= b,
437            _ => false,
438        },
439        WhereOp::Lt => 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::Le => 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::Like => match (value, target) {
452            (String(a), String(b)) => {
453                // 简化 LIKE:将 % 转换为 .*,其他字符转义
454                let pattern = b.replace('%', ".*").replace('_', ".");
455                let full_pattern = format!("^{}$", pattern);
456                if let Ok(re) = simple_regex::compile(&full_pattern) {
457                    re.is_match(a)
458                } else {
459                    false
460                }
461            }
462            _ => false,
463        },
464        WhereOp::In => extras.iter().any(|v| v == value),
465        WhereOp::NotIn => !extras.iter().any(|v| v == value),
466        WhereOp::IsNull => matches!(value, Null),
467        WhereOp::IsNotNull => !matches!(value, Null),
468        WhereOp::Between => {
469            if extras.is_empty() {
470                return false;
471            }
472            let low = target;
473            let high = &extras[0];
474            // value >= low AND value <= high
475            value_matches(value, WhereOp::Ge, low, &[])
476                && value_matches(value, WhereOp::Le, high, &[])
477        }
478    }
479}
480
481/// 实体属性提取 trait(用户为实体实现此 trait 以支持 find_by)
482pub trait EntityAttributes: Send + Sync {
483    /// 按字段名获取属性值
484    fn get_attribute(&self, field: &str) -> Option<Value>;
485}
486
487/// InMemoryRepository 的 EntityAttributes-based 实现
488impl<E: Clone + Send + Sync + 'static + EntityAttributes> Repository<E> for InMemoryRepository<E> {
489    type Key = Value;
490
491    fn key_of(&self, entity: &E) -> Self::Key {
492        entity.get_attribute("id").unwrap_or(Value::Null)
493    }
494
495    fn find_by_id(&self, key: &Self::Key) -> RepositoryResult<Option<E>> {
496        let storage = self.storage.read().unwrap();
497        Ok(storage.iter().find(|e| self.key_of(e) == *key).cloned())
498    }
499
500    fn find_all(&self) -> RepositoryResult<Vec<E>> {
501        let storage = self.storage.read().unwrap();
502        Ok(storage.clone())
503    }
504
505    fn find_by(&self, conditions: &[WhereCondition]) -> RepositoryResult<Vec<E>> {
506        let storage = self.storage.read().unwrap();
507        let result: Vec<E> = storage
508            .iter()
509            .filter(|e| {
510                conditions.iter().all(|c| {
511                    let attr = e.get_attribute(&c.field);
512                    match (attr, c.op) {
513                        (None, WhereOp::IsNull) => true,
514                        (None, _) => false,
515                        (Some(v), _) => value_matches(&v, c.op, &c.value, &c.extra_values),
516                    }
517                })
518            })
519            .cloned()
520            .collect();
521        Ok(result)
522    }
523
524    fn save(&self, mut entity: E) -> RepositoryResult<E> {
525        let mut storage = self.storage.write().unwrap();
526        let key = self.key_of(&entity);
527
528        // 查找是否已存在
529        let existing_idx = storage.iter().position(|e| self.key_of(e) == key);
530
531        match existing_idx {
532            Some(idx) => {
533                storage[idx] = entity.clone();
534            }
535            None => {
536                storage.push(entity.clone());
537            }
538        }
539        // 注意:entity 可能被修改(如自增主键),这里返回原值
540        let _ = &mut entity; // 标记 mut 以符合签名
541        Ok(entity)
542    }
543
544    fn delete(&self, key: &Self::Key) -> RepositoryResult<usize> {
545        let mut storage = self.storage.write().unwrap();
546        let before = storage.len();
547        storage.retain(|e| self.key_of(e) != *key);
548        Ok(before - storage.len())
549    }
550
551    fn count(&self) -> RepositoryResult<u64> {
552        Ok(self.len() as u64)
553    }
554}
555
556// ============================================================================
557// simple_regex — 极简 LIKE 模式匹配(避免引入正则依赖)
558// ============================================================================
559
560mod simple_regex {
561    /// 极简正则编译器:仅支持 `.*`、`^`、`$`、字面字符
562    pub struct Regex {
563        patterns: Vec<Pattern>,
564    }
565
566    enum Pattern {
567        AnyChars,      // .*(贪婪匹配任意字符)
568        Literal(char), // 字面字符
569        Start,         // ^
570        End,           // $
571    }
572
573    pub fn compile(pattern: &str) -> Result<Regex, String> {
574        let mut patterns = Vec::new();
575        let chars: Vec<char> = pattern.chars().collect();
576        let mut i = 0;
577        while i < chars.len() {
578            match chars[i] {
579                '^' => {
580                    patterns.push(Pattern::Start);
581                    i += 1;
582                }
583                '$' => {
584                    patterns.push(Pattern::End);
585                    i += 1;
586                }
587                '.' if i + 1 < chars.len() && chars[i + 1] == '*' => {
588                    patterns.push(Pattern::AnyChars);
589                    i += 2;
590                }
591                c => {
592                    patterns.push(Pattern::Literal(c));
593                    i += 1;
594                }
595            }
596        }
597        Ok(Regex { patterns })
598    }
599
600    impl Regex {
601        pub fn is_match(&self, text: &str) -> bool {
602            self.match_from(text, 0, 0)
603        }
604
605        fn match_from(&self, text: &str, text_idx: usize, pat_idx: usize) -> bool {
606            let chars: Vec<char> = text.chars().collect();
607            if pat_idx >= self.patterns.len() {
608                return text_idx == chars.len();
609            }
610            match &self.patterns[pat_idx] {
611                Pattern::Start => self.match_from(text, 0, pat_idx + 1),
612                Pattern::End => text_idx == chars.len(),
613                Pattern::Literal(c) => {
614                    if text_idx < chars.len() && chars[text_idx] == *c {
615                        self.match_from(text, text_idx + 1, pat_idx + 1)
616                    } else {
617                        false
618                    }
619                }
620                Pattern::AnyChars => {
621                    // 尝试匹配 0 到 len 个字符
622                    for skip in 0..=(chars.len() - text_idx) {
623                        if self.match_from(text, text_idx + skip, pat_idx + 1) {
624                            return true;
625                        }
626                    }
627                    false
628                }
629            }
630        }
631    }
632}
633
634// ============================================================================
635// GenericKeyRepository — 支持任意 Key 类型的内存仓储
636// ============================================================================
637
638/// 通用 Key 提取 trait(用户为实体实现此 trait 以支持任意 Key 类型)
639pub trait EntityKey<K>: Send + Sync {
640    /// 提取主键
641    fn key(&self) -> K;
642}
643
644/// 通用 Key 内存仓储
645pub struct GenericKeyRepository<E, K>
646where
647    E: Clone + Send + Sync + 'static,
648    K: Clone + Debug + PartialEq + Send + Sync + 'static,
649{
650    storage: RwLock<Vec<E>>,
651    _phantom: std::marker::PhantomData<K>,
652}
653
654impl<E, K> GenericKeyRepository<E, K>
655where
656    E: Clone + Send + Sync + 'static,
657    K: Clone + Debug + PartialEq + Send + Sync + 'static,
658{
659    pub fn new() -> Self {
660        Self {
661            storage: RwLock::new(Vec::new()),
662            _phantom: std::marker::PhantomData,
663        }
664    }
665
666    pub fn from_vec(items: Vec<E>) -> Self {
667        Self {
668            storage: RwLock::new(items),
669            _phantom: std::marker::PhantomData,
670        }
671    }
672
673    pub fn len(&self) -> usize {
674        self.storage.read().unwrap().len()
675    }
676
677    pub fn is_empty(&self) -> bool {
678        self.len() == 0
679    }
680
681    pub fn clear(&self) {
682        self.storage.write().unwrap().clear();
683    }
684}
685
686impl<E, K> Default for GenericKeyRepository<E, K>
687where
688    E: Clone + Send + Sync + 'static,
689    K: Clone + Debug + PartialEq + Send + Sync + 'static,
690{
691    fn default() -> Self {
692        Self::new()
693    }
694}
695
696impl<E, K> Repository<E> for GenericKeyRepository<E, K>
697where
698    E: Clone + Send + Sync + 'static + EntityKey<K> + EntityAttributes,
699    K: Clone + Debug + PartialEq + Send + Sync + 'static,
700{
701    type Key = K;
702
703    fn key_of(&self, entity: &E) -> Self::Key {
704        entity.key()
705    }
706
707    fn find_by_id(&self, key: &Self::Key) -> RepositoryResult<Option<E>> {
708        let storage = self.storage.read().unwrap();
709        Ok(storage.iter().find(|e| &e.key() == key).cloned())
710    }
711
712    fn find_all(&self) -> RepositoryResult<Vec<E>> {
713        Ok(self.storage.read().unwrap().clone())
714    }
715
716    fn find_by(&self, conditions: &[WhereCondition]) -> RepositoryResult<Vec<E>> {
717        let storage = self.storage.read().unwrap();
718        let result: Vec<E> = storage
719            .iter()
720            .filter(|e| {
721                conditions.iter().all(|c| {
722                    let attr = e.get_attribute(&c.field);
723                    match (attr, c.op) {
724                        (None, WhereOp::IsNull) => true,
725                        (None, _) => false,
726                        (Some(v), _) => value_matches(&v, c.op, &c.value, &c.extra_values),
727                    }
728                })
729            })
730            .cloned()
731            .collect();
732        Ok(result)
733    }
734
735    fn save(&self, entity: E) -> RepositoryResult<E> {
736        let mut storage = self.storage.write().unwrap();
737        let key = entity.key();
738        let existing_idx = storage.iter().position(|e| e.key() == key);
739        match existing_idx {
740            Some(idx) => {
741                storage[idx] = entity.clone();
742            }
743            None => {
744                storage.push(entity.clone());
745            }
746        }
747        Ok(entity)
748    }
749
750    fn delete(&self, key: &Self::Key) -> RepositoryResult<usize> {
751        let mut storage = self.storage.write().unwrap();
752        let before = storage.len();
753        storage.retain(|e| &e.key() != key);
754        Ok(before - storage.len())
755    }
756
757    fn count(&self) -> RepositoryResult<u64> {
758        Ok(self.len() as u64)
759    }
760}
761
762// ============================================================================
763// 单元测试
764// ============================================================================
765
766#[cfg(test)]
767mod tests {
768    use super::*;
769
770    // ===== 测试用实体 =====
771
772    #[derive(Debug, Clone, PartialEq)]
773    struct User {
774        id: i64,
775        name: String,
776        age: i64,
777        email: String,
778    }
779
780    impl User {
781        fn new(id: i64, name: &str, age: i64, email: &str) -> Self {
782            Self {
783                id,
784                name: name.to_string(),
785                age,
786                email: email.to_string(),
787            }
788        }
789    }
790
791    impl EntityAttributes for User {
792        fn get_attribute(&self, field: &str) -> Option<Value> {
793            match field {
794                "id" => Some(Value::I64(self.id)),
795                "name" => Some(Value::String(self.name.clone())),
796                "age" => Some(Value::I64(self.age)),
797                "email" => Some(Value::String(self.email.clone())),
798                _ => None,
799            }
800        }
801    }
802
803    impl EntityKey<i64> for User {
804        fn key(&self) -> i64 {
805            self.id
806        }
807    }
808
809    // ===== WhereOp / WhereCondition =====
810
811    #[test]
812    fn test_where_op_name() {
813        assert_eq!(WhereOp::Eq.name(), "eq");
814        assert_eq!(WhereOp::Ne.name(), "ne");
815        assert_eq!(WhereOp::Gt.name(), "gt");
816        assert_eq!(WhereOp::Like.name(), "like");
817        assert_eq!(WhereOp::In.name(), "in");
818        assert_eq!(WhereOp::IsNull.name(), "is_null");
819        assert_eq!(WhereOp::Between.name(), "between");
820    }
821
822    #[test]
823    fn test_where_condition_new() {
824        let c = WhereCondition::new("age", WhereOp::Ge, Value::I64(18));
825        assert_eq!(c.field, "age");
826        assert_eq!(c.op, WhereOp::Ge);
827        assert_eq!(c.value, Value::I64(18));
828        assert!(c.extra_values.is_empty());
829    }
830
831    #[test]
832    fn test_where_condition_null_check() {
833        let c = WhereCondition::null_check("deleted_at", WhereOp::IsNull);
834        assert_eq!(c.field, "deleted_at");
835        assert_eq!(c.op, WhereOp::IsNull);
836        assert_eq!(c.value, Value::Null);
837    }
838
839    #[test]
840    fn test_where_condition_in() {
841        let c = WhereCondition::in_op(
842            "id",
843            WhereOp::In,
844            vec![Value::I64(1), Value::I64(2), Value::I64(3)],
845        );
846        assert_eq!(c.field, "id");
847        assert_eq!(c.op, WhereOp::In);
848        assert_eq!(c.extra_values.len(), 3);
849    }
850
851    #[test]
852    fn test_where_condition_between() {
853        let c = WhereCondition::between("age", Value::I64(18), Value::I64(30));
854        assert_eq!(c.field, "age");
855        assert_eq!(c.op, WhereOp::Between);
856        assert_eq!(c.value, Value::I64(18));
857        assert_eq!(c.extra_values, vec![Value::I64(30)]);
858    }
859
860    // ===== PageResult =====
861
862    #[test]
863    fn test_page_result_total_pages() {
864        let pr = PageResult::new(vec![1, 2, 3], 100, 1, 10);
865        assert_eq!(pr.total_pages(), 10);
866    }
867
868    #[test]
869    fn test_page_result_total_pages_with_remainder() {
870        let pr: PageResult<i32> = PageResult::new(vec![], 105, 1, 10);
871        assert_eq!(pr.total_pages(), 11);
872    }
873
874    #[test]
875    fn test_page_result_total_pages_zero_size() {
876        let pr: PageResult<i32> = PageResult::new(vec![], 100, 1, 0);
877        assert_eq!(pr.total_pages(), 0);
878    }
879
880    #[test]
881    fn test_page_result_has_next() {
882        let pr = PageResult::new(vec![1, 2, 3], 100, 1, 10);
883        assert!(pr.has_next());
884        assert!(!pr.has_prev());
885    }
886
887    #[test]
888    fn test_page_result_has_prev() {
889        let pr = PageResult::new(vec![1, 2, 3], 100, 5, 10);
890        assert!(pr.has_prev());
891        assert!(pr.has_next()); // page 5 < total_pages 10
892    }
893
894    #[test]
895    fn test_page_result_is_empty() {
896        let pr: PageResult<i32> = PageResult::new(vec![], 0, 1, 10);
897        assert!(pr.is_empty());
898        assert_eq!(pr.len(), 0);
899    }
900
901    #[test]
902    fn test_page_result_map() {
903        let pr = PageResult::new(vec![1, 2, 3], 100, 1, 10);
904        let mapped = pr.map(|x| x * 2);
905        assert_eq!(mapped.items, vec![2, 4, 6]);
906        assert_eq!(mapped.total, 100);
907    }
908
909    // ===== RepositoryError =====
910
911    #[test]
912    fn test_repository_error_display() {
913        let e = RepositoryError::NotFound;
914        assert_eq!(e.to_string(), "entity not found");
915
916        let e = RepositoryError::DatabaseError("conn refused".to_string());
917        assert_eq!(e.to_string(), "database error: conn refused");
918
919        let e = RepositoryError::InvalidEntity("missing id".to_string());
920        assert_eq!(e.to_string(), "invalid entity: missing id");
921
922        let e = RepositoryError::Other("custom".to_string());
923        assert_eq!(e.to_string(), "repository error: custom");
924    }
925
926    #[test]
927    fn test_repository_error_eq() {
928        assert_eq!(RepositoryError::NotFound, RepositoryError::NotFound);
929        assert_ne!(
930            RepositoryError::NotFound,
931            RepositoryError::Other("x".to_string())
932        );
933    }
934
935    // ===== InMemoryRepository 基础 =====
936
937    #[test]
938    fn test_inmemory_create_empty() {
939        let repo = InMemoryRepository::<User>::new();
940        assert!(repo.is_empty());
941        assert_eq!(repo.len(), 0);
942    }
943
944    #[test]
945    fn test_inmemory_from_vec() {
946        let repo = InMemoryRepository::from_vec(vec![
947            User::new(1, "Alice", 30, "alice@example.com"),
948            User::new(2, "Bob", 25, "bob@example.com"),
949        ]);
950        assert_eq!(repo.len(), 2);
951    }
952
953    #[test]
954    fn test_inmemory_clear() {
955        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
956        assert_eq!(repo.len(), 1);
957        repo.clear();
958        assert_eq!(repo.len(), 0);
959    }
960
961    // ===== Repository trait CRUD =====
962
963    #[test]
964    fn test_repo_save_and_find_by_id() {
965        let repo = InMemoryRepository::<User>::new();
966        let user = User::new(1, "Alice", 30, "alice@example.com");
967        let saved = repo.save(user.clone()).unwrap();
968        assert_eq!(saved, user);
969
970        let found = repo.find_by_id(&Value::I64(1)).unwrap();
971        assert_eq!(found, Some(user));
972    }
973
974    #[test]
975    fn test_repo_find_by_id_missing() {
976        let repo = InMemoryRepository::<User>::new();
977        let found = repo.find_by_id(&Value::I64(999)).unwrap();
978        assert_eq!(found, None);
979    }
980
981    #[test]
982    fn test_repo_save_many() {
983        let repo = InMemoryRepository::<User>::new();
984        let users = vec![
985            User::new(1, "Alice", 30, "alice@example.com"),
986            User::new(2, "Bob", 25, "bob@example.com"),
987            User::new(3, "Carol", 28, "carol@example.com"),
988        ];
989        let saved = repo.save_many(users.clone()).unwrap();
990        assert_eq!(saved.len(), 3);
991        assert_eq!(repo.len(), 3);
992    }
993
994    #[test]
995    fn test_repo_save_update_existing() {
996        let repo = InMemoryRepository::<User>::new();
997        repo.save(User::new(1, "Alice", 30, "alice@example.com"))
998            .unwrap();
999
1000        // 更新
1001        repo.save(User::new(1, "Alice Updated", 31, "alice2@example.com"))
1002            .unwrap();
1003
1004        assert_eq!(repo.len(), 1);
1005        let found = repo.find_by_id(&Value::I64(1)).unwrap().unwrap();
1006        assert_eq!(found.name, "Alice Updated");
1007        assert_eq!(found.age, 31);
1008    }
1009
1010    #[test]
1011    fn test_repo_find_all() {
1012        let repo = InMemoryRepository::from_vec(vec![
1013            User::new(1, "Alice", 30, "a@b.com"),
1014            User::new(2, "Bob", 25, "b@b.com"),
1015        ]);
1016        let all = repo.find_all().unwrap();
1017        assert_eq!(all.len(), 2);
1018    }
1019
1020    #[test]
1021    fn test_repo_find_all_empty() {
1022        let repo = InMemoryRepository::<User>::new();
1023        let all = repo.find_all().unwrap();
1024        assert!(all.is_empty());
1025    }
1026
1027    #[test]
1028    fn test_repo_delete() {
1029        let repo = InMemoryRepository::from_vec(vec![
1030            User::new(1, "Alice", 30, "a@b.com"),
1031            User::new(2, "Bob", 25, "b@b.com"),
1032        ]);
1033        let deleted = repo.delete(&Value::I64(1)).unwrap();
1034        assert_eq!(deleted, 1);
1035        assert_eq!(repo.len(), 1);
1036    }
1037
1038    #[test]
1039    fn test_repo_delete_missing() {
1040        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1041        let deleted = repo.delete(&Value::I64(999)).unwrap();
1042        assert_eq!(deleted, 0);
1043        assert_eq!(repo.len(), 1);
1044    }
1045
1046    #[test]
1047    fn test_repo_count() {
1048        let repo = InMemoryRepository::from_vec(vec![
1049            User::new(1, "Alice", 30, "a@b.com"),
1050            User::new(2, "Bob", 25, "b@b.com"),
1051            User::new(3, "Carol", 28, "c@b.com"),
1052        ]);
1053        assert_eq!(repo.count().unwrap(), 3);
1054    }
1055
1056    #[test]
1057    fn test_repo_count_empty() {
1058        let repo = InMemoryRepository::<User>::new();
1059        assert_eq!(repo.count().unwrap(), 0);
1060    }
1061
1062    #[test]
1063    fn test_repo_exists() {
1064        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1065        assert!(repo.exists(&Value::I64(1)).unwrap());
1066        assert!(!repo.exists(&Value::I64(999)).unwrap());
1067    }
1068
1069    // ===== Repository 条件查询 =====
1070
1071    #[test]
1072    fn test_repo_find_by_eq() {
1073        let repo = InMemoryRepository::from_vec(vec![
1074            User::new(1, "Alice", 30, "a@b.com"),
1075            User::new(2, "Bob", 30, "b@b.com"),
1076            User::new(3, "Carol", 25, "c@b.com"),
1077        ]);
1078
1079        let result = repo
1080            .find_by(&[WhereCondition::new("age", WhereOp::Eq, Value::I64(30))])
1081            .unwrap();
1082        assert_eq!(result.len(), 2);
1083    }
1084
1085    #[test]
1086    fn test_repo_find_by_gt() {
1087        let repo = InMemoryRepository::from_vec(vec![
1088            User::new(1, "Alice", 30, "a@b.com"),
1089            User::new(2, "Bob", 25, "b@b.com"),
1090            User::new(3, "Carol", 35, "c@b.com"),
1091        ]);
1092
1093        let result = repo
1094            .find_by(&[WhereCondition::new("age", WhereOp::Gt, Value::I64(28))])
1095            .unwrap();
1096        assert_eq!(result.len(), 2);
1097    }
1098
1099    #[test]
1100    fn test_repo_find_by_like() {
1101        let repo = InMemoryRepository::from_vec(vec![
1102            User::new(1, "Alice", 30, "alice@example.com"),
1103            User::new(2, "Bob", 25, "bob@example.com"),
1104            User::new(3, "Alicia", 28, "alicia@test.com"),
1105        ]);
1106
1107        let result = repo
1108            .find_by(&[WhereCondition::new(
1109                "name",
1110                WhereOp::Like,
1111                Value::String("Ali%".to_string()),
1112            )])
1113            .unwrap();
1114        assert_eq!(result.len(), 2);
1115    }
1116
1117    #[test]
1118    fn test_repo_find_by_in() {
1119        let repo = InMemoryRepository::from_vec(vec![
1120            User::new(1, "Alice", 30, "a@b.com"),
1121            User::new(2, "Bob", 25, "b@b.com"),
1122            User::new(3, "Carol", 28, "c@b.com"),
1123            User::new(4, "Dave", 32, "d@b.com"),
1124        ]);
1125
1126        let result = repo
1127            .find_by(&[WhereCondition::in_op(
1128                "id",
1129                WhereOp::In,
1130                vec![Value::I64(1), Value::I64(3)],
1131            )])
1132            .unwrap();
1133        assert_eq!(result.len(), 2);
1134    }
1135
1136    #[test]
1137    fn test_repo_find_by_not_in() {
1138        let repo = InMemoryRepository::from_vec(vec![
1139            User::new(1, "Alice", 30, "a@b.com"),
1140            User::new(2, "Bob", 25, "b@b.com"),
1141            User::new(3, "Carol", 28, "c@b.com"),
1142        ]);
1143
1144        let result = repo
1145            .find_by(&[WhereCondition::in_op(
1146                "id",
1147                WhereOp::NotIn,
1148                vec![Value::I64(1)],
1149            )])
1150            .unwrap();
1151        assert_eq!(result.len(), 2);
1152        assert!(result.iter().all(|u| u.id != 1));
1153    }
1154
1155    #[test]
1156    fn test_repo_find_by_between() {
1157        let repo = InMemoryRepository::from_vec(vec![
1158            User::new(1, "Alice", 30, "a@b.com"),
1159            User::new(2, "Bob", 25, "b@b.com"),
1160            User::new(3, "Carol", 35, "c@b.com"),
1161            User::new(4, "Dave", 22, "d@b.com"),
1162        ]);
1163
1164        let result = repo
1165            .find_by(&[WhereCondition::between(
1166                "age",
1167                Value::I64(25),
1168                Value::I64(35),
1169            )])
1170            .unwrap();
1171        assert_eq!(result.len(), 3);
1172    }
1173
1174    #[test]
1175    fn test_repo_find_by_multiple_conditions() {
1176        let repo = InMemoryRepository::from_vec(vec![
1177            User::new(1, "Alice", 30, "a@b.com"),
1178            User::new(2, "Bob", 30, "b@b.com"),
1179            User::new(3, "Alice", 25, "c@b.com"),
1180        ]);
1181
1182        let result = repo
1183            .find_by(&[
1184                WhereCondition::new("name", WhereOp::Eq, Value::String("Alice".to_string())),
1185                WhereCondition::new("age", WhereOp::Ge, Value::I64(30)),
1186            ])
1187            .unwrap();
1188        assert_eq!(result.len(), 1);
1189        assert_eq!(result[0].id, 1);
1190    }
1191
1192    #[test]
1193    fn test_repo_find_one_by() {
1194        let repo = InMemoryRepository::from_vec(vec![
1195            User::new(1, "Alice", 30, "a@b.com"),
1196            User::new(2, "Bob", 25, "b@b.com"),
1197        ]);
1198
1199        let result = repo
1200            .find_one_by(&[WhereCondition::new(
1201                "name",
1202                WhereOp::Eq,
1203                Value::String("Bob".to_string()),
1204            )])
1205            .unwrap();
1206        assert!(result.is_some());
1207        assert_eq!(result.unwrap().id, 2);
1208    }
1209
1210    #[test]
1211    fn test_repo_find_one_by_missing() {
1212        let repo = InMemoryRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1213
1214        let result = repo
1215            .find_one_by(&[WhereCondition::new(
1216                "name",
1217                WhereOp::Eq,
1218                Value::String("Missing".to_string()),
1219            )])
1220            .unwrap();
1221        assert!(result.is_none());
1222    }
1223
1224    #[test]
1225    fn test_repo_count_by() {
1226        let repo = InMemoryRepository::from_vec(vec![
1227            User::new(1, "Alice", 30, "a@b.com"),
1228            User::new(2, "Bob", 30, "b@b.com"),
1229            User::new(3, "Carol", 25, "c@b.com"),
1230        ]);
1231
1232        let count = repo
1233            .count_by(&[WhereCondition::new("age", WhereOp::Eq, Value::I64(30))])
1234            .unwrap();
1235        assert_eq!(count, 2);
1236    }
1237
1238    #[test]
1239    fn test_repo_delete_by() {
1240        let repo = InMemoryRepository::from_vec(vec![
1241            User::new(1, "Alice", 30, "a@b.com"),
1242            User::new(2, "Bob", 30, "b@b.com"),
1243            User::new(3, "Carol", 25, "c@b.com"),
1244        ]);
1245
1246        let deleted = repo
1247            .delete_by(&[WhereCondition::new("age", WhereOp::Eq, Value::I64(30))])
1248            .unwrap();
1249        assert_eq!(deleted, 2);
1250        assert_eq!(repo.len(), 1);
1251    }
1252
1253    // ===== 分页 =====
1254
1255    #[test]
1256    fn test_repo_paginate() {
1257        let users: Vec<User> = (1..=25)
1258            .map(|i| User::new(i, &format!("User{}", i), 20 + (i % 30), "u@b.com"))
1259            .collect();
1260        let repo = InMemoryRepository::from_vec(users);
1261
1262        let page = repo.paginate(1, 10).unwrap();
1263        assert_eq!(page.page, 1);
1264        assert_eq!(page.page_size, 10);
1265        assert_eq!(page.total, 25);
1266        assert_eq!(page.total_pages(), 3);
1267        assert_eq!(page.items.len(), 10);
1268        assert!(page.has_next());
1269        assert!(!page.has_prev());
1270    }
1271
1272    #[test]
1273    fn test_repo_paginate_last_page() {
1274        let users: Vec<User> = (1..=25)
1275            .map(|i| User::new(i, &format!("User{}", i), 20, "u@b.com"))
1276            .collect();
1277        let repo = InMemoryRepository::from_vec(users);
1278
1279        let page = repo.paginate(3, 10).unwrap();
1280        assert_eq!(page.items.len(), 5);
1281        assert!(page.has_prev());
1282        assert!(!page.has_next());
1283    }
1284
1285    #[test]
1286    fn test_repo_paginate_out_of_range() {
1287        let users: Vec<User> = (1..=5)
1288            .map(|i| User::new(i, &format!("User{}", i), 20, "u@b.com"))
1289            .collect();
1290        let repo = InMemoryRepository::from_vec(users);
1291
1292        let page = repo.paginate(10, 10).unwrap();
1293        assert_eq!(page.items.len(), 0);
1294        assert_eq!(page.total, 5);
1295    }
1296
1297    #[test]
1298    fn test_repo_paginate_by() {
1299        let users: Vec<User> = (1..=20)
1300            .map(|i| User::new(i, &format!("User{}", i), 20 + (i % 5), "u@b.com"))
1301            .collect();
1302        let repo = InMemoryRepository::from_vec(users);
1303
1304        // age=22 的用户:i=2,7,12,17 → 4 个
1305        let page = repo
1306            .paginate_by(
1307                &[WhereCondition::new("age", WhereOp::Eq, Value::I64(22))],
1308                1,
1309                2,
1310            )
1311            .unwrap();
1312        assert_eq!(page.total, 4);
1313        assert_eq!(page.items.len(), 2);
1314        assert_eq!(page.total_pages(), 2);
1315    }
1316
1317    // ===== GenericKeyRepository =====
1318
1319    #[test]
1320    fn test_generic_key_repo_basic() {
1321        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::new();
1322        assert!(repo.is_empty());
1323
1324        let user = User::new(1, "Alice", 30, "a@b.com");
1325        repo.save(user.clone()).unwrap();
1326        assert_eq!(repo.len(), 1);
1327
1328        let found = repo.find_by_id(&1).unwrap();
1329        assert_eq!(found, Some(user));
1330    }
1331
1332    #[test]
1333    fn test_generic_key_repo_delete() {
1334        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::from_vec(vec![
1335            User::new(1, "Alice", 30, "a@b.com"),
1336            User::new(2, "Bob", 25, "b@b.com"),
1337        ]);
1338
1339        let deleted = repo.delete(&1).unwrap();
1340        assert_eq!(deleted, 1);
1341        assert_eq!(repo.len(), 1);
1342
1343        let remaining = repo.find_all().unwrap();
1344        assert_eq!(remaining[0].id, 2);
1345    }
1346
1347    #[test]
1348    fn test_generic_key_repo_find_by() {
1349        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::from_vec(vec![
1350            User::new(1, "Alice", 30, "a@b.com"),
1351            User::new(2, "Bob", 30, "b@b.com"),
1352            User::new(3, "Carol", 25, "c@b.com"),
1353        ]);
1354
1355        let result = repo
1356            .find_by(&[WhereCondition::new("age", WhereOp::Eq, Value::I64(30))])
1357            .unwrap();
1358        assert_eq!(result.len(), 2);
1359    }
1360
1361    #[test]
1362    fn test_generic_key_repo_paginate() {
1363        let users: Vec<User> = (1..=15)
1364            .map(|i| User::new(i, &format!("User{}", i), 20, "u@b.com"))
1365            .collect();
1366        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::from_vec(users);
1367
1368        let page = repo.paginate(2, 10).unwrap();
1369        assert_eq!(page.items.len(), 5);
1370        assert_eq!(page.total, 15);
1371        assert_eq!(page.page, 2);
1372    }
1373
1374    #[test]
1375    fn test_generic_key_repo_count() {
1376        let repo: GenericKeyRepository<User, i64> = GenericKeyRepository::from_vec(vec![
1377            User::new(1, "Alice", 30, "a@b.com"),
1378            User::new(2, "Bob", 25, "b@b.com"),
1379        ]);
1380        assert_eq!(repo.count().unwrap(), 2);
1381    }
1382
1383    #[test]
1384    fn test_generic_key_repo_exists() {
1385        let repo: GenericKeyRepository<User, i64> =
1386            GenericKeyRepository::from_vec(vec![User::new(1, "Alice", 30, "a@b.com")]);
1387        assert!(repo.exists(&1).unwrap());
1388        assert!(!repo.exists(&999).unwrap());
1389    }
1390
1391    // ===== simple_regex =====
1392
1393    #[test]
1394    fn test_simple_regex_literal() {
1395        let re = simple_regex::compile("^abc$").unwrap();
1396        assert!(re.is_match("abc"));
1397        assert!(!re.is_match("abcd"));
1398    }
1399
1400    #[test]
1401    fn test_simple_regex_wildcard() {
1402        let re = simple_regex::compile("^Ali.*$").unwrap();
1403        assert!(re.is_match("Alice"));
1404        assert!(re.is_match("Alicia"));
1405        assert!(!re.is_match("Bob"));
1406    }
1407
1408    #[test]
1409    fn test_simple_regex_no_anchors() {
1410        let re = simple_regex::compile("ab").unwrap();
1411        assert!(re.is_match("ab"));
1412    }
1413
1414    // ===== 端到端场景 =====
1415
1416    #[test]
1417    fn test_e2e_repository_workflow() {
1418        let repo = InMemoryRepository::<User>::new();
1419
1420        // 1. 批量插入
1421        let users = vec![
1422            User::new(1, "Alice", 30, "alice@example.com"),
1423            User::new(2, "Bob", 25, "bob@example.com"),
1424            User::new(3, "Carol", 35, "carol@example.com"),
1425            User::new(4, "Dave", 28, "dave@example.com"),
1426            User::new(5, "Eve", 32, "eve@example.com"),
1427        ];
1428        repo.save_many(users).unwrap();
1429        assert_eq!(repo.count().unwrap(), 5);
1430
1431        // 2. 查找成年人(age >= 30)
1432        let adults = repo
1433            .find_by(&[WhereCondition::new("age", WhereOp::Ge, Value::I64(30))])
1434            .unwrap();
1435        assert_eq!(adults.len(), 3);
1436
1437        // 3. 分页查询
1438        let page1 = repo.paginate(1, 2).unwrap();
1439        assert_eq!(page1.items.len(), 2);
1440        assert_eq!(page1.total_pages(), 3);
1441
1442        let page2 = repo.paginate(2, 2).unwrap();
1443        assert_eq!(page2.items.len(), 2);
1444
1445        let page3 = repo.paginate(3, 2).unwrap();
1446        assert_eq!(page3.items.len(), 1);
1447
1448        // 4. 条件分页查询(age >= 30)
1449        let adult_page = repo
1450            .paginate_by(
1451                &[WhereCondition::new("age", WhereOp::Ge, Value::I64(30))],
1452                1,
1453                2,
1454            )
1455            .unwrap();
1456        assert_eq!(adult_page.total, 3);
1457        assert_eq!(adult_page.items.len(), 2);
1458
1459        // 5. 更新
1460        repo.save(User::new(1, "Alice Smith", 31, "alice.smith@example.com"))
1461            .unwrap();
1462        let updated = repo.find_by_id(&Value::I64(1)).unwrap().unwrap();
1463        assert_eq!(updated.name, "Alice Smith");
1464        assert_eq!(updated.age, 31);
1465
1466        // 6. 删除
1467        let deleted = repo.delete(&Value::I64(2)).unwrap();
1468        assert_eq!(deleted, 1);
1469        assert_eq!(repo.count().unwrap(), 4);
1470        assert!(!repo.exists(&Value::I64(2)).unwrap());
1471
1472        // 7. 条件删除 age >= 31:Alice(31) + Carol(35) + Eve(32) = 3 个
1473        let deleted_by = repo
1474            .delete_by(&[WhereCondition::new("age", WhereOp::Ge, Value::I64(31))])
1475            .unwrap();
1476        assert_eq!(deleted_by, 3);
1477        assert_eq!(repo.count().unwrap(), 1); // 仅剩 Dave(28)
1478    }
1479
1480    #[test]
1481    fn test_e2e_pagination_navigation() {
1482        let users: Vec<User> = (1..=100)
1483            .map(|i| User::new(i, &format!("User{}", i), 20, "u@b.com"))
1484            .collect();
1485        let repo = InMemoryRepository::from_vec(users);
1486
1487        let mut current_page = 1u64;
1488        let mut visited: Vec<u64> = Vec::new();
1489        loop {
1490            let page = repo.paginate(current_page, 10).unwrap();
1491            visited.push(current_page);
1492            if !page.has_next() {
1493                break;
1494            }
1495            current_page += 1;
1496        }
1497        assert_eq!(visited.len(), 10);
1498        assert_eq!(visited, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
1499    }
1500}