rust_queries_core/
lock_lazy.rs

1//! Lazy query support for locked data structures.
2//!
3//! Provides lazy evaluation with early termination for locked collections.
4
5use crate::locks::LockValue;
6use key_paths_core::KeyPaths;
7use std::marker::PhantomData;
8
9/// Lazy query for locked data with early termination.
10pub struct LockLazyQuery<'a, T: 'static, L, I>
11where
12    L: LockValue<T> + 'a,
13    I: Iterator<Item = &'a L>,
14{
15    iter: I,
16    _phantom: PhantomData<&'a T>,
17}
18
19impl<'a, T: 'static, L, I> LockLazyQuery<'a, T, L, I>
20where
21    L: LockValue<T> + 'a,
22    I: Iterator<Item = &'a L> + 'a,
23{
24    /// Create a new lazy query from an iterator of locks.
25    pub fn new(iter: I) -> Self {
26        Self {
27            iter,
28            _phantom: PhantomData,
29        }
30    }
31
32    /// Filter using a key-path predicate (lazy).
33    pub fn where_<F, P>(self, path: KeyPaths<T, F>, predicate: P) -> LockLazyQuery<'a, T, L, impl Iterator<Item = &'a L> + 'a>
34    where
35        F: 'static,
36        P: Fn(&F) -> bool + 'a,
37    {
38        LockLazyQuery {
39            iter: self.iter.filter(move |lock| {
40                lock.with_value(|item| {
41                    path.get(item).map_or(false, |val| predicate(val))
42                })
43                .unwrap_or(false)
44            }),
45            _phantom: PhantomData,
46        }
47    }
48
49    /// Map to a field value (lazy).
50    /// 
51    /// This allows you to select only specific fields from locked data without
52    /// cloning the entire object. Perfect for projecting data efficiently.
53    /// 
54    /// # Example
55    /// 
56    /// ```ignore
57    /// // Select only product names (not full objects)
58    /// let names: Vec<String> = products
59    ///     .lock_lazy_query()
60    ///     .where_(Product::price_r(), |&p| p > 100.0)
61    ///     .select_lazy(Product::name_r())
62    ///     .collect();
63    /// 
64    /// // Select only IDs  
65    /// let ids: Vec<u32> = products
66    ///     .lock_lazy_query()
67    ///     .where_(Product::stock_r(), |&s| s > 0)
68    ///     .select_lazy(Product::id_r())
69    ///     .take(10)
70    ///     .collect();
71    /// 
72    /// // Select prices and compute sum
73    /// let total: f64 = products
74    ///     .lock_lazy_query()
75    ///     .where_(Product::category_r(), |c| c == "Electronics")
76    ///     .select_lazy(Product::price_r())
77    ///     .sum();
78    /// ```
79    /// 
80    /// **Performance Note**: This is much more efficient than collecting full objects
81    /// and then extracting fields, as it only clones the specific field value.
82    pub fn select_lazy<F>(self, path: KeyPaths<T, F>) -> impl Iterator<Item = F> + 'a
83    where
84        F: Clone + 'static,
85    {
86        self.iter.filter_map(move |lock| {
87            lock.with_value(|item| path.get(item).cloned()).flatten()
88        })
89    }
90
91    /// Take first N items (lazy).
92    pub fn take_lazy(self, n: usize) -> impl Iterator<Item = T> + 'a
93    where
94        T: Clone,
95    {
96        self.iter
97            .filter_map(|lock| lock.with_value(|item| item.clone()))
98            .take(n)
99    }
100
101    /// Skip first N items (lazy).
102    pub fn skip_lazy(self, n: usize) -> LockLazyQuery<'a, T, L, impl Iterator<Item = &'a L> + 'a> {
103        LockLazyQuery {
104            iter: self.iter.skip(n),
105            _phantom: PhantomData,
106        }
107    }
108
109    /// Count matching items (terminal).
110    pub fn count(self) -> usize {
111        self.iter.count()
112    }
113
114    /// Get first matching item (terminal).
115    pub fn first(mut self) -> Option<T>
116    where
117        T: Clone,
118    {
119        self.iter
120            .find_map(|lock| lock.with_value(|item| item.clone()))
121    }
122
123    /// Check if any items match (terminal).
124    pub fn any(mut self) -> bool {
125        self.iter.next().is_some()
126    }
127
128    /// Collect into Vec (terminal).
129    pub fn collect(self) -> Vec<T>
130    where
131        T: Clone,
132    {
133        self.iter
134            .filter_map(|lock| lock.with_value(|item| item.clone()))
135            .collect()
136    }
137
138    /// Get all matching items (alias for collect, similar to LockQuery::all).
139    /// 
140    /// This provides a familiar API for users coming from LockQuery.
141    /// 
142    /// # Example
143    /// 
144    /// ```ignore
145    /// let all_items: Vec<Product> = products
146    ///     .lock_lazy_query()
147    ///     .where_(Product::price_r(), |&p| p > 100.0)
148    ///     .all();
149    /// ```
150    pub fn all(self) -> Vec<T>
151    where
152        T: Clone,
153    {
154        self.collect()
155    }
156}
157