pub struct Query<'a, T>where
T: 'static,{ /* private fields */ }Expand description
A query builder for filtering, selecting, ordering, grouping, and aggregating data.
§Type Parameters
'a- The lifetime of the data being queriedT- The type of items in the collection
§Example
let products = vec![/* ... */];
let query = Query::new(&products)
.where_(Product::price_r(), |&price| price < 100.0)
.order_by_float(Product::price_r());Implementations§
Source§impl<'a, T> Query<'a, T>where
T: 'static,
impl<'a, T> Query<'a, T>where
T: 'static,
Sourcepub fn new(data: &'a [T]) -> Query<'a, T>
pub fn new(data: &'a [T]) -> Query<'a, T>
Creates a new query from a slice of data.
§Arguments
data- A slice of items to query
§Example
let query = Query::new(&products);Examples found in repository?
27fn main() {
28 println!("Individual Crates Example");
29 println!("=========================\n");
30 println!("Using rust-queries-core + rust-queries-derive directly\n");
31
32 let products = vec![
33 Product {
34 id: 1,
35 name: "Laptop".to_string(),
36 price: 999.99,
37 category: "Electronics".to_string(),
38 stock: 5,
39 },
40 Product {
41 id: 2,
42 name: "Mouse".to_string(),
43 price: 29.99,
44 category: "Electronics".to_string(),
45 stock: 50,
46 },
47 Product {
48 id: 3,
49 name: "Keyboard".to_string(),
50 price: 79.99,
51 category: "Electronics".to_string(),
52 stock: 30,
53 },
54 Product {
55 id: 4,
56 name: "Monitor".to_string(),
57 price: 299.99,
58 category: "Electronics".to_string(),
59 stock: 12,
60 },
61 Product {
62 id: 5,
63 name: "Desk Chair".to_string(),
64 price: 199.99,
65 category: "Furniture".to_string(),
66 stock: 8,
67 },
68 ];
69
70 println!("1. QueryExt from rust_queries_core");
71 println!(" products.query().where_(price > 100).all()");
72
73 let query = products
74 .query() // From QueryExt trait
75 .where_(Product::price_r(), |&p| p > 100.0);
76 let expensive = query.all();
77
78 println!(" Found {} expensive products:", expensive.len());
79 for product in expensive {
80 println!(" - {} (${:.2})", product.name, product.price);
81 }
82 println!();
83
84 println!("2. QueryBuilder from rust_queries_derive");
85 println!(" Product::query(&products).where_(stock < 10).all()");
86
87 let query2 = Product::query(&products) // From QueryBuilder derive
88 .where_(Product::stock_r(), |&s| s < 10);
89 let low_stock = query2.all();
90
91 println!(" Found {} low stock products:", low_stock.len());
92 for product in low_stock {
93 println!(" - {} (stock: {})", product.name, product.stock);
94 }
95 println!();
96
97 println!("3. LazyQuery from rust_queries_core");
98 println!(" products.lazy_query().where_(...).collect()");
99
100 let electronics: Vec<_> = products
101 .lazy_query() // From QueryExt trait
102 .where_(Product::category_r(), |cat| cat == "Electronics")
103 .collect();
104
105 println!(" Found {} electronics:", electronics.len());
106 for product in electronics {
107 println!(" - {}", product.name);
108 }
109 println!();
110
111 println!("4. Aggregations with LazyQuery");
112 println!(" products.lazy_query().sum_by(Product::price_r())");
113
114 let total_value: f64 = products
115 .lazy_query()
116 .sum_by(Product::price_r());
117
118 println!(" Total inventory value: ${:.2}", total_value);
119 println!();
120
121 println!("5. Early termination with lazy queries");
122 println!(" products.lazy_query().where_(...).first()");
123
124 if let Some(first_cheap) = products
125 .lazy_query()
126 .where_(Product::price_r(), |&p| p < 50.0)
127 .first()
128 {
129 println!(" First cheap product: {} (${:.2})", first_cheap.name, first_cheap.price);
130 }
131 println!();
132
133 println!("6. Using Query (eager) from rust_queries_core");
134 println!(" Query::new(&products).where_(...).count()");
135
136 let query3 = Query::new(&products) // Traditional approach
137 .where_(Product::price_r(), |&p| p > 50.0);
138 let count = query3.count();
139
140 println!(" Products over $50: {}", count);
141 println!();
142
143 println!("Summary:");
144 println!("--------");
145 println!("✓ rust_queries_core provides: Query, LazyQuery, QueryExt");
146 println!("✓ rust_queries_derive provides: #[derive(QueryBuilder)]");
147 println!("✓ key_paths_derive provides: #[derive(Keypaths)]");
148 println!("✓ All features work with individual crates!");
149}More examples
28fn main() {
29 println!("╔════════════════════════════════════════════════════════════╗");
30 println!("║ Query Builder Without Clone - Performance Optimization ║");
31 println!("╚════════════════════════════════════════════════════════════╝\n");
32
33 let employees = vec![
34 Employee {
35 id: 1,
36 name: "Alice".to_string(),
37 email: "alice@example.com".to_string(),
38 department: "Engineering".to_string(),
39 salary: 95000.0,
40 large_data: vec![0; 1000], // Large data - expensive to clone!
41 },
42 Employee {
43 id: 2,
44 name: "Bob".to_string(),
45 email: "bob@example.com".to_string(),
46 department: "Engineering".to_string(),
47 salary: 87000.0,
48 large_data: vec![0; 1000],
49 },
50 Employee {
51 id: 3,
52 name: "Carol".to_string(),
53 email: "carol@example.com".to_string(),
54 department: "Sales".to_string(),
55 salary: 75000.0,
56 large_data: vec![0; 1000],
57 },
58 ];
59
60 let departments = vec![
61 Department {
62 id: 1,
63 name: "Engineering".to_string(),
64 budget: 1000000.0,
65 },
66 Department {
67 id: 2,
68 name: "Sales".to_string(),
69 budget: 500000.0,
70 },
71 ];
72
73 println!("✅ Operations that DON'T require Clone:\n");
74
75 // 1. WHERE filtering - returns Vec<&T>
76 println!("1. WHERE filtering (returns references)");
77 let query = Query::new(&employees)
78 .where_(Employee::department_r(), |dept| dept == "Engineering");
79 let engineering = query.all();
80 println!(" Found {} engineering employees", engineering.len());
81 for emp in &engineering {
82 println!(" - {}: ${:.0}", emp.name, emp.salary);
83 }
84
85 // 2. COUNT - no cloning needed
86 println!("\n2. COUNT aggregation");
87 let count = Query::new(&employees)
88 .where_(Employee::salary_r(), |&sal| sal > 80000.0)
89 .count();
90 println!(" {} employees earn over $80k", count);
91
92 // 3. SELECT - only clones the selected field
93 println!("\n3. SELECT (only selected fields are cloned)");
94 let names: Vec<String> = Query::new(&employees)
95 .select(Employee::name_r());
96 println!(" Employee names: {:?}", names);
97
98 // 4. FIRST - returns Option<&T>
99 println!("\n4. FIRST (returns reference)");
100 let query = Query::new(&employees)
101 .where_(Employee::salary_r(), |&sal| sal > 90000.0);
102 if let Some(emp) = query.first() {
103 println!(" First high earner: {} (${:.0})", emp.name, emp.salary);
104 }
105
106 // 5. SUM/AVG aggregations - no cloning
107 println!("\n5. Aggregations (SUM/AVG)");
108 let eng_query = Query::new(&employees)
109 .where_(Employee::department_r(), |dept| dept == "Engineering");
110 let total = eng_query.sum(Employee::salary_r());
111 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
112 println!(" Engineering total: ${:.0}", total);
113 println!(" Engineering average: ${:.0}", avg);
114
115 // 6. MIN/MAX - no cloning
116 println!("\n6. MIN/MAX");
117 let min = Query::new(&employees).min_float(Employee::salary_r());
118 let max = Query::new(&employees).max_float(Employee::salary_r());
119 println!(" Salary range: ${:.0} - ${:.0}", min.unwrap(), max.unwrap());
120
121 // 7. LIMIT - returns Vec<&T>
122 println!("\n7. LIMIT (returns references)");
123 let query = Query::new(&employees);
124 let first_two = query.limit(2);
125 println!(" First 2 employees:");
126 for emp in &first_two {
127 println!(" - {}", emp.name);
128 }
129
130 // 8. SKIP/Pagination - returns Vec<&T>
131 println!("\n8. SKIP/Pagination (returns references)");
132 let query = Query::new(&employees);
133 let page_2 = query.skip(2).limit(1);
134 println!(" Page 2:");
135 for emp in &page_2 {
136 println!(" - {}", emp.name);
137 }
138
139 // 9. EXISTS - just checks
140 println!("\n9. EXISTS check");
141 let has_sales = Query::new(&employees)
142 .where_(Employee::department_r(), |dept| dept == "Sales")
143 .exists();
144 println!(" Has Sales employees: {}", has_sales);
145
146 // 10. JOIN - no Clone required on L or R!
147 println!("\n10. JOIN operations (no Clone required!)");
148 let results = JoinQuery::new(&employees, &departments)
149 .inner_join(
150 Employee::department_r(),
151 Department::name_r(),
152 |emp, dept| {
153 // Mapper only clones what it needs for the result
154 (emp.name.clone(), dept.budget)
155 },
156 );
157 println!(" Employee-Department pairs:");
158 for (name, budget) in &results {
159 println!(" - {} works in dept with ${:.0} budget", name, budget);
160 }
161
162 println!("\n╔════════════════════════════════════════════════════════════╗");
163 println!("║ Operations that REQUIRE Clone (only when needed) ║");
164 println!("╚════════════════════════════════════════════════════════════╝\n");
165
166 println!("⚠️ The following operations require Clone because they return owned Vec<T>:");
167 println!(" - order_by() / order_by_desc()");
168 println!(" - order_by_float() / order_by_float_desc()");
169 println!(" - group_by()");
170 println!("\n To use these, add #[derive(Clone)] to your struct:");
171 println!(" ```rust");
172 println!(" #[derive(Clone, Keypaths)] // Add Clone here");
173 println!(" struct Employee {{ ... }}");
174 println!(" ```");
175
176 println!("\n╔════════════════════════════════════════════════════════════╗");
177 println!("║ Performance Benefits ║");
178 println!("╚════════════════════════════════════════════════════════════╝\n");
179
180 println!("✅ Zero cloning for most operations");
181 println!("✅ Work with large structs efficiently");
182 println!("✅ No unnecessary memory allocations");
183 println!("✅ Only clone when you actually need owned data");
184 println!("✅ Pay for what you use");
185
186 println!("\n✓ Example complete! Most operations work without Clone.\n");
187}30fn main() {
31 println!("Testing documentation examples...\n");
32
33 // Example from README - Quick Start
34 println!("Test 1: README Quick Start Example");
35 {
36 let products = vec![
37 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
38 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
39 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
40 ];
41
42 let affordable_query = Query::new(&products)
43 .where_(Product::category_r(), |cat| cat == "Electronics")
44 .where_(Product::price_r(), |&price| price < 100.0);
45 let affordable_electronics = affordable_query.all();
46
47 println!(" Found {} affordable electronics ✅", affordable_electronics.len());
48 }
49
50 // Example from README - Filtering
51 println!("\nTest 2: Filtering Example");
52 {
53 let products = vec![
54 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
55 ];
56
57 let electronics_query = Query::new(&products)
58 .where_(Product::category_r(), |cat| cat == "Electronics");
59 let electronics = electronics_query.all();
60
61 println!(" Found {} electronics ✅", electronics.len());
62 }
63
64 // Example from README - Selecting
65 println!("\nTest 3: Selecting Fields Example");
66 {
67 let products = vec![
68 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
69 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
70 ];
71
72 let names: Vec<String> = Query::new(&products)
73 .select(Product::name_r());
74
75 println!(" Selected {} names ✅", names.len());
76 }
77
78 // Example from README - Ordering
79 println!("\nTest 4: Ordering Example");
80 {
81 let products = vec![
82 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
83 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
84 ];
85
86 let by_price = Query::new(&products).order_by_float(Product::price_r());
87 println!(" Ordered {} products ✅", by_price.len());
88 }
89
90 // Example from README - Aggregations
91 println!("\nTest 5: Aggregations Example");
92 {
93 let products = vec![
94 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
95 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
96 ];
97
98 let electronics_query = Query::new(&products)
99 .where_(Product::category_r(), |cat| cat == "Electronics");
100
101 let count = electronics_query.count();
102 let total_value: f64 = electronics_query.sum(Product::price_r());
103 let avg_price = electronics_query.avg(Product::price_r()).unwrap_or(0.0);
104
105 println!(" Count: {}, Total: ${:.2}, Avg: ${:.2} ✅", count, total_value, avg_price);
106 }
107
108 // Example from README - Grouping
109 println!("\nTest 6: Grouping Example");
110 {
111 let products = vec![
112 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
113 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
114 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
115 ];
116
117 let by_category = Query::new(&products).group_by(Product::category_r());
118 println!(" Grouped into {} categories ✅", by_category.len());
119 }
120
121 // Example from README - Pagination
122 println!("\nTest 7: Pagination Example");
123 {
124 let products = vec![
125 Product { id: 1, name: "P1".to_string(), price: 10.0, category: "A".to_string(), stock: 1, rating: 4.0 },
126 Product { id: 2, name: "P2".to_string(), price: 20.0, category: "A".to_string(), stock: 1, rating: 4.0 },
127 Product { id: 3, name: "P3".to_string(), price: 30.0, category: "A".to_string(), stock: 1, rating: 4.0 },
128 ];
129
130 let query = Query::new(&products);
131 let first_10 = query.limit(10);
132 let page_1 = query.skip(0).limit(10);
133
134 println!(" Limited to {} products ✅", first_10.len());
135 println!(" Page 1 has {} products ✅", page_1.len());
136 }
137
138 // Example from README - Join
139 println!("\nTest 8: Join Example");
140 {
141 let users = vec![
142 User { id: 1, name: "Alice".to_string() },
143 User { id: 2, name: "Bob".to_string() },
144 ];
145
146 let orders = vec![
147 Order { id: 101, user_id: 1, total: 99.99 },
148 Order { id: 102, user_id: 1, total: 149.99 },
149 ];
150
151 let user_orders = JoinQuery::new(&users, &orders).inner_join(
152 User::id_r(),
153 Order::user_id_r(),
154 |user, order| (user.name.clone(), order.total),
155 );
156
157 println!(" Joined {} user-order pairs ✅", user_orders.len());
158 }
159
160 // Example from SQL_COMPARISON - SELECT with WHERE
161 println!("\nTest 9: SQL Comparison - SELECT with WHERE");
162 {
163 #[derive(Clone, Keypaths)]
164 struct Employee {
165 department: String,
166 }
167
168 let employees = vec![
169 Employee { department: "Engineering".to_string() },
170 Employee { department: "Sales".to_string() },
171 ];
172
173 let engineering_query = Query::new(&employees)
174 .where_(Employee::department_r(), |dept| dept == "Engineering");
175 let engineering = engineering_query.all();
176
177 println!(" Found {} engineering employees ✅", engineering.len());
178 }
179
180 // Example from USAGE.md - Complex Filtering
181 println!("\nTest 10: USAGE - Complex Filtering");
182 {
183 let products = vec![
184 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
185 ];
186
187 let results_query = Query::new(&products)
188 .where_(Product::category_r(), |cat| cat == "Electronics")
189 .where_(Product::price_r(), |&price| price >= 100.0 && price <= 500.0)
190 .where_(Product::stock_r(), |&stock| stock > 10);
191 let results = results_query.order_by_float(Product::price_r());
192
193 println!(" Filtered {} products ✅", results.len());
194 }
195
196 println!("\n✅ All documentation examples compile and run successfully!");
197}110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}33fn main() {
34 let employees = create_test_data();
35
36 println!("\n╔════════════════════════════════════════════════════════════════╗");
37 println!("║ SQL Equivalence Verification Tests ║");
38 println!("╚════════════════════════════════════════════════════════════════╝\n");
39
40 // TEST 1: ORDER BY maintains exact SQL ordering (DESC)
41 println!("Test 1: ORDER BY DESC - Exact ordering");
42 println!("SQL: SELECT * FROM employees ORDER BY salary DESC;");
43
44 let ordered = Query::new(&employees).order_by_float_desc(Employee::salary_r());
45 let expected_order = vec![105000.0, 95000.0, 87000.0, 82000.0, 75000.0, 71000.0];
46 let actual_order: Vec<f64> = ordered.iter().map(|e| e.salary).collect();
47
48 let test1_pass = expected_order == actual_order;
49 print_test("ORDER BY salary DESC produces correct order", test1_pass);
50 if !test1_pass {
51 println!(" Expected: {:?}", expected_order);
52 println!(" Got: {:?}", actual_order);
53 }
54
55 // TEST 2: ORDER BY maintains exact SQL ordering (ASC)
56 println!("\nTest 2: ORDER BY ASC - Exact ordering");
57 println!("SQL: SELECT * FROM employees ORDER BY salary ASC;");
58
59 let ordered_asc = Query::new(&employees).order_by_float(Employee::salary_r());
60 let expected_asc = vec![71000.0, 75000.0, 82000.0, 87000.0, 95000.0, 105000.0];
61 let actual_asc: Vec<f64> = ordered_asc.iter().map(|e| e.salary).collect();
62
63 let test2_pass = expected_asc == actual_asc;
64 print_test("ORDER BY salary ASC produces correct order", test2_pass);
65 if !test2_pass {
66 println!(" Expected: {:?}", expected_asc);
67 println!(" Got: {:?}", actual_asc);
68 }
69
70 // TEST 3: String ordering (alphabetical)
71 println!("\nTest 3: ORDER BY name (alphabetical)");
72 println!("SQL: SELECT name FROM employees ORDER BY name;");
73
74 let ordered_names = Query::new(&employees).order_by(Employee::name_r());
75 let expected_names = vec!["Alice Cooper", "Alice Johnson", "Bob Smith", "Carol White", "David Brown", "Eve Davis"];
76 let actual_names: Vec<&str> = ordered_names.iter().map(|e| e.name.as_str()).collect();
77
78 let test3_pass = expected_names == actual_names;
79 print_test("ORDER BY name produces correct alphabetical order", test3_pass);
80 if !test3_pass {
81 println!(" Expected: {:?}", expected_names);
82 println!(" Got: {:?}", actual_names);
83 }
84
85 // TEST 4: LIKE equivalent - starts with
86 println!("\nTest 4: LIKE 'Alice%' equivalent");
87 println!("SQL: SELECT * FROM employees WHERE name LIKE 'Alice%';");
88
89 let like_alice_query = Query::new(&employees)
90 .where_(Employee::name_r(), |name| name.starts_with("Alice"));
91 let like_alice = like_alice_query.all();
92
93 let test4_pass = like_alice.len() == 2
94 && like_alice.iter().all(|e| e.name.starts_with("Alice"));
95 print_test("LIKE 'Alice%' (starts_with) works correctly", test4_pass);
96 if test4_pass {
97 for emp in &like_alice {
98 println!(" Found: {}", emp.name);
99 }
100 }
101
102 // TEST 5: LIKE equivalent - ends with
103 println!("\nTest 5: LIKE '%son' equivalent");
104 println!("SQL: SELECT * FROM employees WHERE name LIKE '%son';");
105
106 let like_son_query = Query::new(&employees)
107 .where_(Employee::name_r(), |name| name.ends_with("son"));
108 let like_son = like_son_query.all();
109
110 let test5_pass = like_son.len() == 1 && like_son[0].name == "Alice Johnson";
111 print_test("LIKE '%son' (ends_with) works correctly", test5_pass);
112 if test5_pass {
113 for emp in &like_son {
114 println!(" Found: {}", emp.name);
115 }
116 }
117
118 // TEST 6: LIKE equivalent - contains
119 println!("\nTest 6: LIKE '%mit%' equivalent");
120 println!("SQL: SELECT * FROM employees WHERE name LIKE '%mit%';");
121
122 let like_mit_query = Query::new(&employees)
123 .where_(Employee::name_r(), |name| name.contains("mit"));
124 let like_mit = like_mit_query.all();
125
126 let test6_pass = like_mit.len() == 1 && like_mit[0].name == "Bob Smith";
127 print_test("LIKE '%mit%' (contains) works correctly", test6_pass);
128 if test6_pass {
129 for emp in &like_mit {
130 println!(" Found: {}", emp.name);
131 }
132 }
133
134 // TEST 7: IN clause equivalent
135 println!("\nTest 7: IN clause equivalent");
136 println!("SQL: SELECT * FROM employees WHERE department IN ('Engineering', 'Sales');");
137
138 let in_depts_query = Query::new(&employees)
139 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales");
140 let in_depts = in_depts_query.all();
141
142 let test7_pass = in_depts.len() == 5 // 3 Engineering + 2 Sales
143 && in_depts.iter().all(|e| e.department == "Engineering" || e.department == "Sales");
144 print_test("IN clause works correctly", test7_pass);
145 println!(" Found {} employees in Engineering or Sales", in_depts.len());
146
147 // TEST 8: BETWEEN equivalent
148 println!("\nTest 8: BETWEEN clause equivalent");
149 println!("SQL: SELECT * FROM employees WHERE salary BETWEEN 75000 AND 90000;");
150
151 let between_query = Query::new(&employees)
152 .where_(Employee::salary_r(), |&sal| sal >= 75000.0 && sal <= 90000.0);
153 let between = between_query.all();
154
155 let test8_pass = between.len() == 3;
156 print_test("BETWEEN clause works correctly", test8_pass);
157 println!(" Found {} employees with salary between 75K-90K", between.len());
158
159 // TEST 9: COUNT with WHERE
160 println!("\nTest 9: COUNT with WHERE");
161 println!("SQL: SELECT COUNT(*) FROM employees WHERE department = 'Engineering';");
162
163 let count_eng = Query::new(&employees)
164 .where_(Employee::department_r(), |dept| dept == "Engineering")
165 .count();
166
167 let test9_pass = count_eng == 3;
168 print_test("COUNT with WHERE produces correct result", test9_pass);
169 println!(" Count: {} (expected 3)", count_eng);
170
171 // TEST 10: AVG produces exact result
172 println!("\nTest 10: AVG aggregation accuracy");
173 println!("SQL: SELECT AVG(salary) FROM employees WHERE department = 'Engineering';");
174
175 let avg_sal = Query::new(&employees)
176 .where_(Employee::department_r(), |dept| dept == "Engineering")
177 .avg(Employee::salary_r())
178 .unwrap_or(0.0);
179
180 let expected_avg = (95000.0 + 87000.0 + 105000.0) / 3.0;
181 let test10_pass = (avg_sal - expected_avg).abs() < 0.01;
182 print_test("AVG produces mathematically correct result", test10_pass);
183 println!(" Average: ${:.2} (expected ${:.2})", avg_sal, expected_avg);
184
185 // TEST 11: MIN and MAX
186 println!("\nTest 11: MIN and MAX aggregations");
187 println!("SQL: SELECT MIN(salary), MAX(salary) FROM employees;");
188
189 let min_sal = Query::new(&employees).min_float(Employee::salary_r()).unwrap_or(0.0);
190 let max_sal = Query::new(&employees).max_float(Employee::salary_r()).unwrap_or(0.0);
191
192 let test11_pass = min_sal == 71000.0 && max_sal == 105000.0;
193 print_test("MIN and MAX produce correct results", test11_pass);
194 println!(" MIN: ${:.2}, MAX: ${:.2}", min_sal, max_sal);
195
196 // TEST 12: Complex WHERE with AND/OR
197 println!("\nTest 12: Complex WHERE (AND + OR)");
198 println!("SQL: SELECT * FROM employees WHERE (department = 'Engineering' OR department = 'Sales') AND salary > 80000;");
199
200 let complex_query = Query::new(&employees)
201 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
202 .where_(Employee::salary_r(), |&sal| sal > 80000.0);
203 let complex = complex_query.all();
204
205 let test12_pass = complex.len() == 4; // Alice J ($95k), Bob ($87k), David ($82k), Alice C ($105k)
206 print_test("Complex WHERE clause works correctly", test12_pass);
207 println!(" Found {} employees", complex.len());
208
209 // TEST 13: Case-sensitive string comparison (SQL default)
210 println!("\nTest 13: Case-sensitive comparison (like SQL)");
211 println!("SQL: SELECT * FROM employees WHERE department = 'engineering'; -- should find 0");
212
213 let case_sensitive = Query::new(&employees)
214 .where_(Employee::department_r(), |dept| dept == "engineering") // lowercase
215 .count();
216
217 let test13_pass = case_sensitive == 0;
218 print_test("Case-sensitive comparison (SQL default)", test13_pass);
219 println!(" Found {} with lowercase 'engineering' (expected 0)", case_sensitive);
220
221 // TEST 14: Case-insensitive LIKE equivalent
222 println!("\nTest 14: Case-insensitive LIKE (ILIKE equivalent)");
223 println!("SQL: SELECT * FROM employees WHERE LOWER(name) LIKE '%alice%';");
224
225 let ilike_query = Query::new(&employees)
226 .where_(Employee::name_r(), |name| name.to_lowercase().contains("alice"));
227 let ilike = ilike_query.all();
228
229 let test14_pass = ilike.len() == 2;
230 print_test("Case-insensitive LIKE works correctly", test14_pass);
231 println!(" Found {} employees with 'alice' (case-insensitive)", ilike.len());
232
233 // TEST 15: LIMIT produces exact subset
234 println!("\nTest 15: LIMIT clause");
235 println!("SQL: SELECT * FROM employees ORDER BY salary DESC LIMIT 3;");
236
237 let limited = Query::new(&employees)
238 .order_by_float_desc(Employee::salary_r())
239 .into_iter()
240 .take(3)
241 .collect::<Vec<_>>();
242
243 let test15_pass = limited.len() == 3
244 && limited[0].salary == 105000.0
245 && limited[1].salary == 95000.0
246 && limited[2].salary == 87000.0;
247 print_test("LIMIT returns correct top-N results", test15_pass);
248 println!(" Top 3 salaries: ${:.0}, ${:.0}, ${:.0}",
249 limited[0].salary, limited[1].salary, limited[2].salary);
250
251 // TEST 16: GROUP BY produces correct groups
252 println!("\nTest 16: GROUP BY");
253 println!("SQL: SELECT department, COUNT(*) FROM employees GROUP BY department;");
254
255 let grouped = Query::new(&employees).group_by(Employee::department_r());
256 let eng_count = grouped.get("Engineering").map(|v| v.len()).unwrap_or(0);
257 let sales_count = grouped.get("Sales").map(|v| v.len()).unwrap_or(0);
258 let marketing_count = grouped.get("Marketing").map(|v| v.len()).unwrap_or(0);
259
260 let test16_pass = eng_count == 3 && sales_count == 2 && marketing_count == 1;
261 print_test("GROUP BY produces correct counts", test16_pass);
262 println!(" Engineering: {}, Sales: {}, Marketing: {}", eng_count, sales_count, marketing_count);
263
264 // TEST 17: Email pattern matching (regex-like)
265 println!("\nTest 17: Email domain filtering (LIKE '%@example.com')");
266 println!("SQL: SELECT * FROM employees WHERE email LIKE '%@example.com';");
267
268 let example_emails = Query::new(&employees)
269 .where_(Employee::email_r(), |email| email.ends_with("@example.com"))
270 .count();
271
272 let test17_pass = example_emails == 6; // All employees have @example.com emails
273 print_test("Email pattern matching works correctly", test17_pass);
274 println!(" Found {} employees with @example.com emails", example_emails);
275
276 // Summary
277 println!("\n╔════════════════════════════════════════════════════════════════╗");
278 println!("║ Test Summary ║");
279 println!("╚════════════════════════════════════════════════════════════════╝\n");
280
281 let tests = vec![
282 ("ORDER BY DESC", test1_pass),
283 ("ORDER BY ASC", test2_pass),
284 ("ORDER BY name", test3_pass),
285 ("LIKE 'prefix%'", test4_pass),
286 ("LIKE '%suffix'", test5_pass),
287 ("LIKE '%contains%'", test6_pass),
288 ("IN clause", test7_pass),
289 ("BETWEEN clause", test8_pass),
290 ("COUNT", test9_pass),
291 ("AVG accuracy", test10_pass),
292 ("MIN/MAX", test11_pass),
293 ("Complex WHERE", test12_pass),
294 ("Case-sensitive", test13_pass),
295 ("Case-insensitive", test14_pass),
296 ("LIMIT", test15_pass),
297 ("GROUP BY", test16_pass),
298 ("Email patterns", test17_pass),
299 ];
300
301 let passed = tests.iter().filter(|(_, p)| *p).count();
302 let total = tests.len();
303
304 println!("Results: {}/{} tests passed", passed, total);
305
306 if passed == total {
307 println!("\n🎉 All tests PASSED! Rust Query Builder produces exact SQL-equivalent results!");
308 println!("\n✅ Verified:");
309 println!(" • Exact ordering (ASC/DESC)");
310 println!(" • LIKE operations (starts_with, ends_with, contains)");
311 println!(" • IN clause (OR conditions)");
312 println!(" • BETWEEN clause");
313 println!(" • Aggregations (COUNT, AVG, MIN, MAX)");
314 println!(" • Complex WHERE conditions");
315 println!(" • Case sensitivity");
316 println!(" • LIMIT clause");
317 println!(" • GROUP BY");
318 println!(" • Pattern matching");
319 } else {
320 println!("\n⚠️ {} test(s) failed. See details above.", total - passed);
321 }
322}26fn main() {
27 println!("\n╔════════════════════════════════════════════════════════════════╗");
28 println!("║ Container Support Demo ║");
29 println!("║ Query various collection types ║");
30 println!("╚════════════════════════════════════════════════════════════════╝\n");
31
32 // ============================================================================
33 // CONTAINER 1: Vec<T>
34 // ============================================================================
35 println!("═══════════════════════════════════════════════════════════════");
36 println!("Container 1: Vec<T>");
37 println!("═══════════════════════════════════════════════════════════════\n");
38
39 let vec_products = vec![
40 create_sample_product(1, "Laptop", 999, "Electronics"),
41 create_sample_product(2, "Mouse", 29, "Electronics"),
42 create_sample_product(3, "Desk", 299, "Furniture"),
43 ];
44
45 // Query Vec directly
46 let vec_query = Query::new(&vec_products)
47 .where_(Product::category_r(), |cat| cat == "Electronics");
48 let vec_results = vec_query.all();
49 println!(" Vec: Found {} electronics", vec_results.len());
50
51 // Lazy query on Vec
52 let lazy_count = LazyQuery::new(&vec_products)
53 .where_(Product::price_r(), |&p| p < 100)
54 .count();
55 println!(" Vec (lazy): {} items under $100", lazy_count);
56
57 // ============================================================================
58 // CONTAINER 2: VecDeque<T>
59 // ============================================================================
60 println!("\n═══════════════════════════════════════════════════════════════");
61 println!("Container 2: VecDeque<T>");
62 println!("═══════════════════════════════════════════════════════════════\n");
63
64 let mut deque_products = VecDeque::new();
65 deque_products.push_back(create_sample_product(1, "Keyboard", 129, "Electronics"));
66 deque_products.push_back(create_sample_product(2, "Monitor", 349, "Electronics"));
67 deque_products.push_back(create_sample_product(3, "Chair", 199, "Furniture"));
68
69 // Convert to owned Vec for querying
70 let deque_vec: Vec<Product> = deque_products.iter().cloned().collect();
71 let deque_query = Query::new(&deque_vec);
72 let deque_count = deque_query.count();
73 println!(" VecDeque: {} total items", deque_count);
74
75 // More efficient: use make_contiguous for zero-copy slice access
76 let contiguous = deque_products.make_contiguous();
77 let contiguous_query = Query::new(contiguous);
78 println!(" VecDeque (zero-copy): {} items", contiguous_query.count());
79
80 // ============================================================================
81 // CONTAINER 3: HashSet<T>
82 // ============================================================================
83 println!("\n═══════════════════════════════════════════════════════════════");
84 println!("Container 3: HashSet<T>");
85 println!("═══════════════════════════════════════════════════════════════\n");
86
87 let mut set_products = HashSet::new();
88 set_products.insert(create_sample_product(1, "Tablet", 499, "Electronics"));
89 set_products.insert(create_sample_product(2, "Phone", 799, "Electronics"));
90 set_products.insert(create_sample_product(3, "Lamp", 39, "Furniture"));
91
92 // Collect from HashSet to Vec for querying
93 let set_vec: Vec<Product> = set_products.iter().cloned().collect();
94 let set_query = Query::new(&set_vec)
95 .where_(Product::price_r(), |&p| p > 500);
96 let expensive = set_query.all();
97 println!(" HashSet: {} expensive items", expensive.len());
98
99 // Lazy on HashSet (convert to owned Vec first)
100 let set_owned: Vec<Product> = set_products.iter().cloned().collect();
101 let lazy_set: Vec<_> = LazyQuery::new(&set_owned)
102 .where_(Product::category_r(), |cat| cat == "Electronics")
103 .collect();
104 println!(" HashSet (lazy): {} electronics", lazy_set.len());
105
106 // ============================================================================
107 // CONTAINER 4: BTreeSet<T>
108 // ============================================================================
109 println!("\n═══════════════════════════════════════════════════════════════");
110 println!("Container 4: BTreeSet<T>");
111 println!("═══════════════════════════════════════════════════════════════\n");
112
113 let mut btree_set = BTreeSet::new();
114 btree_set.insert(create_sample_product(1, "Webcam", 79, "Electronics"));
115 btree_set.insert(create_sample_product(2, "Microphone", 129, "Electronics"));
116 btree_set.insert(create_sample_product(3, "Bookshelf", 149, "Furniture"));
117
118 let btree_vec: Vec<Product> = btree_set.iter().cloned().collect();
119 let btree_query = Query::new(&btree_vec);
120 println!(" BTreeSet: {} total items (sorted order!)", btree_query.count());
121
122 // BTreeSet items are in sorted order
123 for (i, item) in btree_vec.iter().take(3).enumerate() {
124 println!(" {}. {} (ID: {})", i + 1, item.name, item.id);
125 }
126
127 // ============================================================================
128 // CONTAINER 5: HashMap<K, V> - Query Values
129 // ============================================================================
130 println!("\n═══════════════════════════════════════════════════════════════");
131 println!("Container 5: HashMap<K, V> - Querying values");
132 println!("═══════════════════════════════════════════════════════════════\n");
133
134 let mut map_products = HashMap::new();
135 map_products.insert("prod1", create_sample_product(1, "Speaker", 199, "Electronics"));
136 map_products.insert("prod2", create_sample_product(2, "Headphones", 149, "Electronics"));
137 map_products.insert("prod3", create_sample_product(3, "Ottoman", 249, "Furniture"));
138
139 // Query HashMap values (convert to owned Vec)
140 let map_vec: Vec<Product> = map_products.values().cloned().collect();
141 let map_query = Query::new(&map_vec)
142 .where_(Product::category_r(), |cat| cat == "Electronics");
143 let electronics = map_query.all();
144 println!(" HashMap: {} electronics", electronics.len());
145
146 // ============================================================================
147 // CONTAINER 6: BTreeMap<K, V> - Query Values
148 // ============================================================================
149 println!("\n═══════════════════════════════════════════════════════════════");
150 println!("Container 6: BTreeMap<K, V> - Querying values");
151 println!("═══════════════════════════════════════════════════════════════\n");
152
153 let mut btree_map = BTreeMap::new();
154 btree_map.insert(1, create_sample_product(1, "Router", 89, "Electronics"));
155 btree_map.insert(2, create_sample_product(2, "Switch", 129, "Electronics"));
156 btree_map.insert(3, create_sample_product(3, "Sofa", 899, "Furniture"));
157
158 let btree_map_vec: Vec<Product> = btree_map.values().cloned().collect();
159 let btree_map_query = Query::new(&btree_map_vec);
160 let avg_price = btree_map_query.sum(Product::price_r()) as f64 / btree_map.len() as f64;
161 println!(" BTreeMap: Average price ${:.2}", avg_price);
162
163 // ============================================================================
164 // CONTAINER 7: Arrays [T; N]
165 // ============================================================================
166 println!("\n═══════════════════════════════════════════════════════════════");
167 println!("Container 7: Arrays [T; N]");
168 println!("═══════════════════════════════════════════════════════════════\n");
169
170 let array_products = [
171 create_sample_product(1, "USB Cable", 15, "Electronics"),
172 create_sample_product(2, "HDMI Cable", 25, "Electronics"),
173 create_sample_product(3, "Power Strip", 35, "Electronics"),
174 ];
175
176 // Query array directly (as slice)
177 let array_query = Query::new(&array_products);
178 let total = array_query.sum(Product::price_r());
179 println!(" Array: Total value ${}", total);
180
181 // Lazy on array
182 let lazy_array: Vec<_> = LazyQuery::new(&array_products)
183 .where_(Product::price_r(), |&p| p > 20)
184 .collect();
185 println!(" Array (lazy): {} items over $20", lazy_array.len());
186
187 // ============================================================================
188 // CONTAINER 8: LinkedList<T>
189 // ============================================================================
190 println!("\n═══════════════════════════════════════════════════════════════");
191 println!("Container 8: LinkedList<T>");
192 println!("═══════════════════════════════════════════════════════════════\n");
193
194 let mut list_products = LinkedList::new();
195 list_products.push_back(create_sample_product(1, "SSD", 159, "Electronics"));
196 list_products.push_back(create_sample_product(2, "HDD", 79, "Electronics"));
197
198 let list_vec: Vec<Product> = list_products.iter().cloned().collect();
199 let list_query = Query::new(&list_vec);
200 println!(" LinkedList: {} items", list_query.count());
201
202 // ============================================================================
203 // CONTAINER 9: Option<T> and Result<T, E>
204 // ============================================================================
205 println!("\n═══════════════════════════════════════════════════════════════");
206 println!("Container 9: Option<T> and Result<T, E>");
207 println!("═══════════════════════════════════════════════════════════════\n");
208
209 let maybe_product = Some(create_sample_product(1, "Mystery Box", 99, "Special"));
210
211 if let Some(ref product) = maybe_product {
212 let option_query = Query::new(std::slice::from_ref(product));
213 println!(" Option (Some): {} items", option_query.count());
214 }
215
216 let none_product: Option<Product> = None;
217 let none_count = none_product.iter().count();
218 println!(" Option (None): {} items", none_count);
219
220 // ============================================================================
221 // Summary
222 // ============================================================================
223 println!("\n╔════════════════════════════════════════════════════════════════╗");
224 println!("║ Supported Containers Summary ║");
225 println!("╚════════════════════════════════════════════════════════════════╝\n");
226
227 println!("✅ Supported container types:");
228 println!(" • Vec<T> - Standard vector");
229 println!(" • &[T] - Slices");
230 println!(" • [T; N] - Fixed-size arrays");
231 println!(" • VecDeque<T> - Double-ended queue");
232 println!(" • LinkedList<T> - Doubly-linked list");
233 println!(" • HashSet<T> - Unordered set");
234 println!(" • BTreeSet<T> - Ordered set");
235 println!(" • HashMap<K, V> - Query values");
236 println!(" • BTreeMap<K, V> - Query values (sorted)");
237 println!(" • Option<T> - 0 or 1 item");
238 println!(" • Result<T, E> - 0 or 1 item\n");
239
240 println!("📝 Usage patterns:");
241 println!(" • Direct: Query::new(&container) for Vec, slices, arrays");
242 println!(" • Convert: Collect to Vec for Sets and Maps");
243 println!(" • Lazy: LazyQuery::new(&slice) for any slice\n");
244
245 println!("💡 Tips:");
246 println!(" • Vec/slice: Direct support, most efficient");
247 println!(" • Sets: Iterate to Vec, then query");
248 println!(" • Maps: Use .values().collect() to query values");
249 println!(" • VecDeque: Use .as_slices() for zero-copy");
250 println!(" • For custom types: Implement Queryable trait\n");
251
252 println!("✓ Container support demo complete!\n");
253}Sourcepub fn where_<F>(
self,
path: KeyPaths<T, F>,
predicate: impl Fn(&F) -> bool + 'static,
) -> Query<'a, T>where
F: 'static,
pub fn where_<F>(
self,
path: KeyPaths<T, F>,
predicate: impl Fn(&F) -> bool + 'static,
) -> Query<'a, T>where
F: 'static,
Adds a filter predicate using a key-path.
§Arguments
path- The key-path to the field to filter onpredicate- A function that returns true for items to keep
§Example
let query = Query::new(&products)
.where_(Product::category_r(), |cat| cat == "Electronics");Examples found in repository?
27fn main() {
28 println!("Individual Crates Example");
29 println!("=========================\n");
30 println!("Using rust-queries-core + rust-queries-derive directly\n");
31
32 let products = vec![
33 Product {
34 id: 1,
35 name: "Laptop".to_string(),
36 price: 999.99,
37 category: "Electronics".to_string(),
38 stock: 5,
39 },
40 Product {
41 id: 2,
42 name: "Mouse".to_string(),
43 price: 29.99,
44 category: "Electronics".to_string(),
45 stock: 50,
46 },
47 Product {
48 id: 3,
49 name: "Keyboard".to_string(),
50 price: 79.99,
51 category: "Electronics".to_string(),
52 stock: 30,
53 },
54 Product {
55 id: 4,
56 name: "Monitor".to_string(),
57 price: 299.99,
58 category: "Electronics".to_string(),
59 stock: 12,
60 },
61 Product {
62 id: 5,
63 name: "Desk Chair".to_string(),
64 price: 199.99,
65 category: "Furniture".to_string(),
66 stock: 8,
67 },
68 ];
69
70 println!("1. QueryExt from rust_queries_core");
71 println!(" products.query().where_(price > 100).all()");
72
73 let query = products
74 .query() // From QueryExt trait
75 .where_(Product::price_r(), |&p| p > 100.0);
76 let expensive = query.all();
77
78 println!(" Found {} expensive products:", expensive.len());
79 for product in expensive {
80 println!(" - {} (${:.2})", product.name, product.price);
81 }
82 println!();
83
84 println!("2. QueryBuilder from rust_queries_derive");
85 println!(" Product::query(&products).where_(stock < 10).all()");
86
87 let query2 = Product::query(&products) // From QueryBuilder derive
88 .where_(Product::stock_r(), |&s| s < 10);
89 let low_stock = query2.all();
90
91 println!(" Found {} low stock products:", low_stock.len());
92 for product in low_stock {
93 println!(" - {} (stock: {})", product.name, product.stock);
94 }
95 println!();
96
97 println!("3. LazyQuery from rust_queries_core");
98 println!(" products.lazy_query().where_(...).collect()");
99
100 let electronics: Vec<_> = products
101 .lazy_query() // From QueryExt trait
102 .where_(Product::category_r(), |cat| cat == "Electronics")
103 .collect();
104
105 println!(" Found {} electronics:", electronics.len());
106 for product in electronics {
107 println!(" - {}", product.name);
108 }
109 println!();
110
111 println!("4. Aggregations with LazyQuery");
112 println!(" products.lazy_query().sum_by(Product::price_r())");
113
114 let total_value: f64 = products
115 .lazy_query()
116 .sum_by(Product::price_r());
117
118 println!(" Total inventory value: ${:.2}", total_value);
119 println!();
120
121 println!("5. Early termination with lazy queries");
122 println!(" products.lazy_query().where_(...).first()");
123
124 if let Some(first_cheap) = products
125 .lazy_query()
126 .where_(Product::price_r(), |&p| p < 50.0)
127 .first()
128 {
129 println!(" First cheap product: {} (${:.2})", first_cheap.name, first_cheap.price);
130 }
131 println!();
132
133 println!("6. Using Query (eager) from rust_queries_core");
134 println!(" Query::new(&products).where_(...).count()");
135
136 let query3 = Query::new(&products) // Traditional approach
137 .where_(Product::price_r(), |&p| p > 50.0);
138 let count = query3.count();
139
140 println!(" Products over $50: {}", count);
141 println!();
142
143 println!("Summary:");
144 println!("--------");
145 println!("✓ rust_queries_core provides: Query, LazyQuery, QueryExt");
146 println!("✓ rust_queries_derive provides: #[derive(QueryBuilder)]");
147 println!("✓ key_paths_derive provides: #[derive(Keypaths)]");
148 println!("✓ All features work with individual crates!");
149}More examples
13fn main() {
14 println!("Derive Macros and Extension Traits Example");
15 println!("===========================================\n");
16
17 let products = vec![
18 Product {
19 id: 1,
20 name: "Laptop".to_string(),
21 price: 999.99,
22 category: "Electronics".to_string(),
23 stock: 5,
24 },
25 Product {
26 id: 2,
27 name: "Mouse".to_string(),
28 price: 29.99,
29 category: "Electronics".to_string(),
30 stock: 50,
31 },
32 Product {
33 id: 3,
34 name: "Keyboard".to_string(),
35 price: 79.99,
36 category: "Electronics".to_string(),
37 stock: 30,
38 },
39 Product {
40 id: 4,
41 name: "Monitor".to_string(),
42 price: 299.99,
43 category: "Electronics".to_string(),
44 stock: 12,
45 },
46 Product {
47 id: 5,
48 name: "Desk Chair".to_string(),
49 price: 199.99,
50 category: "Furniture".to_string(),
51 stock: 8,
52 },
53 ];
54
55 println!("1. Using Extension Trait - Direct .query() on Vec");
56 println!(" Query: products.query().where_(price > 100).all()");
57
58 let query = products
59 .query()
60 .where_(Product::price_r(), |&p| p > 100.0);
61 let expensive = query.all();
62
63 println!(" Found {} expensive products:", expensive.len());
64 for product in &expensive {
65 println!(" - {} (${:.2})", product.name, product.price);
66 }
67 println!();
68
69 println!("2. Using Extension Trait - Direct .lazy_query() on Vec");
70 println!(" Query: products.lazy_query().where_(stock < 10).collect()");
71
72 let low_stock: Vec<_> = products
73 .lazy_query()
74 .where_(Product::stock_r(), |&s| s < 10)
75 .collect();
76
77 println!(" Found {} low stock products:", low_stock.len());
78 for product in &low_stock {
79 println!(" - {} (stock: {})", product.name, product.stock);
80 }
81 println!();
82
83 println!("3. Using Extension Trait - Chained Operations");
84 println!(" Query: products.lazy_query().where_(category == Electronics).take(2).select(name).collect()");
85
86 let names: Vec<String> = products
87 .lazy_query()
88 .where_(Product::category_r(), |cat| cat == "Electronics")
89 .take_lazy(2)
90 .select_lazy(Product::name_r())
91 .collect();
92
93 println!(" First 2 electronics:");
94 for name in &names {
95 println!(" - {}", name);
96 }
97 println!();
98
99 println!("4. Using QueryBuilder Derive - Static Methods");
100 println!(" Query: Product::query(&products).where_(price > 50).count()");
101
102 let query4 = Product::query(&products)
103 .where_(Product::price_r(), |&p| p > 50.0);
104 let count = query4.count();
105
106 println!(" Products over $50: {}", count);
107 println!();
108
109 println!("5. Using QueryBuilder Derive - Lazy Static Methods");
110 println!(" Query: Product::lazy_query(&products).first()");
111
112 if let Some(first) = Product::lazy_query(&products).first() {
113 println!(" First product: {} (${:.2})", first.name, first.price);
114 }
115 println!();
116
117 println!("6. Complex Chain with Extension Trait");
118 println!(" Query: products.lazy_query()");
119 println!(" .where_(category == Electronics)");
120 println!(" .where_(price < 500)");
121 println!(" .map(|p| format!(\"{{}} - ${{:.2}}\", p.name, p.price))");
122 println!(" .collect()");
123
124 let formatted: Vec<String> = products
125 .lazy_query()
126 .where_(Product::category_r(), |cat| cat == "Electronics")
127 .where_(Product::price_r(), |&p| p < 500.0)
128 .map_items(|p| format!("{} - ${:.2}", p.name, p.price))
129 .collect();
130
131 println!(" Affordable electronics:");
132 for item in &formatted {
133 println!(" - {}", item);
134 }
135 println!();
136
137 println!("7. Aggregation with Extension Trait");
138 println!(" Query: products.lazy_query().sum_by(Product::stock())");
139
140 let total_stock = products
141 .lazy_query()
142 .sum_by(Product::stock_r());
143
144 println!(" Total stock across all products: {}", total_stock);
145 println!();
146
147 println!("8. Find with Extension Trait");
148 println!(" Query: products.lazy_query().find(|p| p.name.contains(\"Chair\"))");
149
150 if let Some(chair) = products.lazy_query().find(|p| p.name.contains("Chair")) {
151 println!(" Found: {} in {}", chair.name, chair.category);
152 }
153 println!();
154
155 println!("9. Early Termination with Extension Trait");
156 println!(" Query: products.lazy_query().where_(price > 1000).any()");
157
158 let has_luxury = products
159 .lazy_query()
160 .where_(Product::price_r(), |&p| p > 1000.0)
161 .any();
162
163 println!(" Has products over $1000: {}", has_luxury);
164 println!();
165
166 println!("10. Slice Extension Trait");
167 println!(" Query: (&products[..]).lazy_query().count()");
168
169 let slice_count = (&products[..])
170 .lazy_query()
171 .count();
172
173 println!(" Count from slice: {}", slice_count);
174 println!();
175
176 println!("Summary:");
177 println!("--------");
178 println!("✓ Extension trait QueryExt adds .query() and .lazy_query() to containers");
179 println!("✓ Derive macro QueryBuilder adds static methods Product::query() and Product::lazy_query()");
180 println!("✓ Both approaches provide the same query functionality");
181 println!("✓ Extension trait is more ergonomic: products.query() vs Query::new(&products)");
182 println!("✓ All iterator optimizations (fusion, early termination) still apply");
183}28fn main() {
29 println!("╔════════════════════════════════════════════════════════════╗");
30 println!("║ Query Builder Without Clone - Performance Optimization ║");
31 println!("╚════════════════════════════════════════════════════════════╝\n");
32
33 let employees = vec![
34 Employee {
35 id: 1,
36 name: "Alice".to_string(),
37 email: "alice@example.com".to_string(),
38 department: "Engineering".to_string(),
39 salary: 95000.0,
40 large_data: vec![0; 1000], // Large data - expensive to clone!
41 },
42 Employee {
43 id: 2,
44 name: "Bob".to_string(),
45 email: "bob@example.com".to_string(),
46 department: "Engineering".to_string(),
47 salary: 87000.0,
48 large_data: vec![0; 1000],
49 },
50 Employee {
51 id: 3,
52 name: "Carol".to_string(),
53 email: "carol@example.com".to_string(),
54 department: "Sales".to_string(),
55 salary: 75000.0,
56 large_data: vec![0; 1000],
57 },
58 ];
59
60 let departments = vec![
61 Department {
62 id: 1,
63 name: "Engineering".to_string(),
64 budget: 1000000.0,
65 },
66 Department {
67 id: 2,
68 name: "Sales".to_string(),
69 budget: 500000.0,
70 },
71 ];
72
73 println!("✅ Operations that DON'T require Clone:\n");
74
75 // 1. WHERE filtering - returns Vec<&T>
76 println!("1. WHERE filtering (returns references)");
77 let query = Query::new(&employees)
78 .where_(Employee::department_r(), |dept| dept == "Engineering");
79 let engineering = query.all();
80 println!(" Found {} engineering employees", engineering.len());
81 for emp in &engineering {
82 println!(" - {}: ${:.0}", emp.name, emp.salary);
83 }
84
85 // 2. COUNT - no cloning needed
86 println!("\n2. COUNT aggregation");
87 let count = Query::new(&employees)
88 .where_(Employee::salary_r(), |&sal| sal > 80000.0)
89 .count();
90 println!(" {} employees earn over $80k", count);
91
92 // 3. SELECT - only clones the selected field
93 println!("\n3. SELECT (only selected fields are cloned)");
94 let names: Vec<String> = Query::new(&employees)
95 .select(Employee::name_r());
96 println!(" Employee names: {:?}", names);
97
98 // 4. FIRST - returns Option<&T>
99 println!("\n4. FIRST (returns reference)");
100 let query = Query::new(&employees)
101 .where_(Employee::salary_r(), |&sal| sal > 90000.0);
102 if let Some(emp) = query.first() {
103 println!(" First high earner: {} (${:.0})", emp.name, emp.salary);
104 }
105
106 // 5. SUM/AVG aggregations - no cloning
107 println!("\n5. Aggregations (SUM/AVG)");
108 let eng_query = Query::new(&employees)
109 .where_(Employee::department_r(), |dept| dept == "Engineering");
110 let total = eng_query.sum(Employee::salary_r());
111 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
112 println!(" Engineering total: ${:.0}", total);
113 println!(" Engineering average: ${:.0}", avg);
114
115 // 6. MIN/MAX - no cloning
116 println!("\n6. MIN/MAX");
117 let min = Query::new(&employees).min_float(Employee::salary_r());
118 let max = Query::new(&employees).max_float(Employee::salary_r());
119 println!(" Salary range: ${:.0} - ${:.0}", min.unwrap(), max.unwrap());
120
121 // 7. LIMIT - returns Vec<&T>
122 println!("\n7. LIMIT (returns references)");
123 let query = Query::new(&employees);
124 let first_two = query.limit(2);
125 println!(" First 2 employees:");
126 for emp in &first_two {
127 println!(" - {}", emp.name);
128 }
129
130 // 8. SKIP/Pagination - returns Vec<&T>
131 println!("\n8. SKIP/Pagination (returns references)");
132 let query = Query::new(&employees);
133 let page_2 = query.skip(2).limit(1);
134 println!(" Page 2:");
135 for emp in &page_2 {
136 println!(" - {}", emp.name);
137 }
138
139 // 9. EXISTS - just checks
140 println!("\n9. EXISTS check");
141 let has_sales = Query::new(&employees)
142 .where_(Employee::department_r(), |dept| dept == "Sales")
143 .exists();
144 println!(" Has Sales employees: {}", has_sales);
145
146 // 10. JOIN - no Clone required on L or R!
147 println!("\n10. JOIN operations (no Clone required!)");
148 let results = JoinQuery::new(&employees, &departments)
149 .inner_join(
150 Employee::department_r(),
151 Department::name_r(),
152 |emp, dept| {
153 // Mapper only clones what it needs for the result
154 (emp.name.clone(), dept.budget)
155 },
156 );
157 println!(" Employee-Department pairs:");
158 for (name, budget) in &results {
159 println!(" - {} works in dept with ${:.0} budget", name, budget);
160 }
161
162 println!("\n╔════════════════════════════════════════════════════════════╗");
163 println!("║ Operations that REQUIRE Clone (only when needed) ║");
164 println!("╚════════════════════════════════════════════════════════════╝\n");
165
166 println!("⚠️ The following operations require Clone because they return owned Vec<T>:");
167 println!(" - order_by() / order_by_desc()");
168 println!(" - order_by_float() / order_by_float_desc()");
169 println!(" - group_by()");
170 println!("\n To use these, add #[derive(Clone)] to your struct:");
171 println!(" ```rust");
172 println!(" #[derive(Clone, Keypaths)] // Add Clone here");
173 println!(" struct Employee {{ ... }}");
174 println!(" ```");
175
176 println!("\n╔════════════════════════════════════════════════════════════╗");
177 println!("║ Performance Benefits ║");
178 println!("╚════════════════════════════════════════════════════════════╝\n");
179
180 println!("✅ Zero cloning for most operations");
181 println!("✅ Work with large structs efficiently");
182 println!("✅ No unnecessary memory allocations");
183 println!("✅ Only clone when you actually need owned data");
184 println!("✅ Pay for what you use");
185
186 println!("\n✓ Example complete! Most operations work without Clone.\n");
187}30fn main() {
31 println!("Testing documentation examples...\n");
32
33 // Example from README - Quick Start
34 println!("Test 1: README Quick Start Example");
35 {
36 let products = vec![
37 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
38 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
39 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
40 ];
41
42 let affordable_query = Query::new(&products)
43 .where_(Product::category_r(), |cat| cat == "Electronics")
44 .where_(Product::price_r(), |&price| price < 100.0);
45 let affordable_electronics = affordable_query.all();
46
47 println!(" Found {} affordable electronics ✅", affordable_electronics.len());
48 }
49
50 // Example from README - Filtering
51 println!("\nTest 2: Filtering Example");
52 {
53 let products = vec![
54 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
55 ];
56
57 let electronics_query = Query::new(&products)
58 .where_(Product::category_r(), |cat| cat == "Electronics");
59 let electronics = electronics_query.all();
60
61 println!(" Found {} electronics ✅", electronics.len());
62 }
63
64 // Example from README - Selecting
65 println!("\nTest 3: Selecting Fields Example");
66 {
67 let products = vec![
68 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
69 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
70 ];
71
72 let names: Vec<String> = Query::new(&products)
73 .select(Product::name_r());
74
75 println!(" Selected {} names ✅", names.len());
76 }
77
78 // Example from README - Ordering
79 println!("\nTest 4: Ordering Example");
80 {
81 let products = vec![
82 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
83 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
84 ];
85
86 let by_price = Query::new(&products).order_by_float(Product::price_r());
87 println!(" Ordered {} products ✅", by_price.len());
88 }
89
90 // Example from README - Aggregations
91 println!("\nTest 5: Aggregations Example");
92 {
93 let products = vec![
94 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
95 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
96 ];
97
98 let electronics_query = Query::new(&products)
99 .where_(Product::category_r(), |cat| cat == "Electronics");
100
101 let count = electronics_query.count();
102 let total_value: f64 = electronics_query.sum(Product::price_r());
103 let avg_price = electronics_query.avg(Product::price_r()).unwrap_or(0.0);
104
105 println!(" Count: {}, Total: ${:.2}, Avg: ${:.2} ✅", count, total_value, avg_price);
106 }
107
108 // Example from README - Grouping
109 println!("\nTest 6: Grouping Example");
110 {
111 let products = vec![
112 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
113 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
114 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
115 ];
116
117 let by_category = Query::new(&products).group_by(Product::category_r());
118 println!(" Grouped into {} categories ✅", by_category.len());
119 }
120
121 // Example from README - Pagination
122 println!("\nTest 7: Pagination Example");
123 {
124 let products = vec![
125 Product { id: 1, name: "P1".to_string(), price: 10.0, category: "A".to_string(), stock: 1, rating: 4.0 },
126 Product { id: 2, name: "P2".to_string(), price: 20.0, category: "A".to_string(), stock: 1, rating: 4.0 },
127 Product { id: 3, name: "P3".to_string(), price: 30.0, category: "A".to_string(), stock: 1, rating: 4.0 },
128 ];
129
130 let query = Query::new(&products);
131 let first_10 = query.limit(10);
132 let page_1 = query.skip(0).limit(10);
133
134 println!(" Limited to {} products ✅", first_10.len());
135 println!(" Page 1 has {} products ✅", page_1.len());
136 }
137
138 // Example from README - Join
139 println!("\nTest 8: Join Example");
140 {
141 let users = vec![
142 User { id: 1, name: "Alice".to_string() },
143 User { id: 2, name: "Bob".to_string() },
144 ];
145
146 let orders = vec![
147 Order { id: 101, user_id: 1, total: 99.99 },
148 Order { id: 102, user_id: 1, total: 149.99 },
149 ];
150
151 let user_orders = JoinQuery::new(&users, &orders).inner_join(
152 User::id_r(),
153 Order::user_id_r(),
154 |user, order| (user.name.clone(), order.total),
155 );
156
157 println!(" Joined {} user-order pairs ✅", user_orders.len());
158 }
159
160 // Example from SQL_COMPARISON - SELECT with WHERE
161 println!("\nTest 9: SQL Comparison - SELECT with WHERE");
162 {
163 #[derive(Clone, Keypaths)]
164 struct Employee {
165 department: String,
166 }
167
168 let employees = vec![
169 Employee { department: "Engineering".to_string() },
170 Employee { department: "Sales".to_string() },
171 ];
172
173 let engineering_query = Query::new(&employees)
174 .where_(Employee::department_r(), |dept| dept == "Engineering");
175 let engineering = engineering_query.all();
176
177 println!(" Found {} engineering employees ✅", engineering.len());
178 }
179
180 // Example from USAGE.md - Complex Filtering
181 println!("\nTest 10: USAGE - Complex Filtering");
182 {
183 let products = vec![
184 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
185 ];
186
187 let results_query = Query::new(&products)
188 .where_(Product::category_r(), |cat| cat == "Electronics")
189 .where_(Product::price_r(), |&price| price >= 100.0 && price <= 500.0)
190 .where_(Product::stock_r(), |&stock| stock > 10);
191 let results = results_query.order_by_float(Product::price_r());
192
193 println!(" Filtered {} products ✅", results.len());
194 }
195
196 println!("\n✅ All documentation examples compile and run successfully!");
197}110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}33fn main() {
34 let employees = create_test_data();
35
36 println!("\n╔════════════════════════════════════════════════════════════════╗");
37 println!("║ SQL Equivalence Verification Tests ║");
38 println!("╚════════════════════════════════════════════════════════════════╝\n");
39
40 // TEST 1: ORDER BY maintains exact SQL ordering (DESC)
41 println!("Test 1: ORDER BY DESC - Exact ordering");
42 println!("SQL: SELECT * FROM employees ORDER BY salary DESC;");
43
44 let ordered = Query::new(&employees).order_by_float_desc(Employee::salary_r());
45 let expected_order = vec![105000.0, 95000.0, 87000.0, 82000.0, 75000.0, 71000.0];
46 let actual_order: Vec<f64> = ordered.iter().map(|e| e.salary).collect();
47
48 let test1_pass = expected_order == actual_order;
49 print_test("ORDER BY salary DESC produces correct order", test1_pass);
50 if !test1_pass {
51 println!(" Expected: {:?}", expected_order);
52 println!(" Got: {:?}", actual_order);
53 }
54
55 // TEST 2: ORDER BY maintains exact SQL ordering (ASC)
56 println!("\nTest 2: ORDER BY ASC - Exact ordering");
57 println!("SQL: SELECT * FROM employees ORDER BY salary ASC;");
58
59 let ordered_asc = Query::new(&employees).order_by_float(Employee::salary_r());
60 let expected_asc = vec![71000.0, 75000.0, 82000.0, 87000.0, 95000.0, 105000.0];
61 let actual_asc: Vec<f64> = ordered_asc.iter().map(|e| e.salary).collect();
62
63 let test2_pass = expected_asc == actual_asc;
64 print_test("ORDER BY salary ASC produces correct order", test2_pass);
65 if !test2_pass {
66 println!(" Expected: {:?}", expected_asc);
67 println!(" Got: {:?}", actual_asc);
68 }
69
70 // TEST 3: String ordering (alphabetical)
71 println!("\nTest 3: ORDER BY name (alphabetical)");
72 println!("SQL: SELECT name FROM employees ORDER BY name;");
73
74 let ordered_names = Query::new(&employees).order_by(Employee::name_r());
75 let expected_names = vec!["Alice Cooper", "Alice Johnson", "Bob Smith", "Carol White", "David Brown", "Eve Davis"];
76 let actual_names: Vec<&str> = ordered_names.iter().map(|e| e.name.as_str()).collect();
77
78 let test3_pass = expected_names == actual_names;
79 print_test("ORDER BY name produces correct alphabetical order", test3_pass);
80 if !test3_pass {
81 println!(" Expected: {:?}", expected_names);
82 println!(" Got: {:?}", actual_names);
83 }
84
85 // TEST 4: LIKE equivalent - starts with
86 println!("\nTest 4: LIKE 'Alice%' equivalent");
87 println!("SQL: SELECT * FROM employees WHERE name LIKE 'Alice%';");
88
89 let like_alice_query = Query::new(&employees)
90 .where_(Employee::name_r(), |name| name.starts_with("Alice"));
91 let like_alice = like_alice_query.all();
92
93 let test4_pass = like_alice.len() == 2
94 && like_alice.iter().all(|e| e.name.starts_with("Alice"));
95 print_test("LIKE 'Alice%' (starts_with) works correctly", test4_pass);
96 if test4_pass {
97 for emp in &like_alice {
98 println!(" Found: {}", emp.name);
99 }
100 }
101
102 // TEST 5: LIKE equivalent - ends with
103 println!("\nTest 5: LIKE '%son' equivalent");
104 println!("SQL: SELECT * FROM employees WHERE name LIKE '%son';");
105
106 let like_son_query = Query::new(&employees)
107 .where_(Employee::name_r(), |name| name.ends_with("son"));
108 let like_son = like_son_query.all();
109
110 let test5_pass = like_son.len() == 1 && like_son[0].name == "Alice Johnson";
111 print_test("LIKE '%son' (ends_with) works correctly", test5_pass);
112 if test5_pass {
113 for emp in &like_son {
114 println!(" Found: {}", emp.name);
115 }
116 }
117
118 // TEST 6: LIKE equivalent - contains
119 println!("\nTest 6: LIKE '%mit%' equivalent");
120 println!("SQL: SELECT * FROM employees WHERE name LIKE '%mit%';");
121
122 let like_mit_query = Query::new(&employees)
123 .where_(Employee::name_r(), |name| name.contains("mit"));
124 let like_mit = like_mit_query.all();
125
126 let test6_pass = like_mit.len() == 1 && like_mit[0].name == "Bob Smith";
127 print_test("LIKE '%mit%' (contains) works correctly", test6_pass);
128 if test6_pass {
129 for emp in &like_mit {
130 println!(" Found: {}", emp.name);
131 }
132 }
133
134 // TEST 7: IN clause equivalent
135 println!("\nTest 7: IN clause equivalent");
136 println!("SQL: SELECT * FROM employees WHERE department IN ('Engineering', 'Sales');");
137
138 let in_depts_query = Query::new(&employees)
139 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales");
140 let in_depts = in_depts_query.all();
141
142 let test7_pass = in_depts.len() == 5 // 3 Engineering + 2 Sales
143 && in_depts.iter().all(|e| e.department == "Engineering" || e.department == "Sales");
144 print_test("IN clause works correctly", test7_pass);
145 println!(" Found {} employees in Engineering or Sales", in_depts.len());
146
147 // TEST 8: BETWEEN equivalent
148 println!("\nTest 8: BETWEEN clause equivalent");
149 println!("SQL: SELECT * FROM employees WHERE salary BETWEEN 75000 AND 90000;");
150
151 let between_query = Query::new(&employees)
152 .where_(Employee::salary_r(), |&sal| sal >= 75000.0 && sal <= 90000.0);
153 let between = between_query.all();
154
155 let test8_pass = between.len() == 3;
156 print_test("BETWEEN clause works correctly", test8_pass);
157 println!(" Found {} employees with salary between 75K-90K", between.len());
158
159 // TEST 9: COUNT with WHERE
160 println!("\nTest 9: COUNT with WHERE");
161 println!("SQL: SELECT COUNT(*) FROM employees WHERE department = 'Engineering';");
162
163 let count_eng = Query::new(&employees)
164 .where_(Employee::department_r(), |dept| dept == "Engineering")
165 .count();
166
167 let test9_pass = count_eng == 3;
168 print_test("COUNT with WHERE produces correct result", test9_pass);
169 println!(" Count: {} (expected 3)", count_eng);
170
171 // TEST 10: AVG produces exact result
172 println!("\nTest 10: AVG aggregation accuracy");
173 println!("SQL: SELECT AVG(salary) FROM employees WHERE department = 'Engineering';");
174
175 let avg_sal = Query::new(&employees)
176 .where_(Employee::department_r(), |dept| dept == "Engineering")
177 .avg(Employee::salary_r())
178 .unwrap_or(0.0);
179
180 let expected_avg = (95000.0 + 87000.0 + 105000.0) / 3.0;
181 let test10_pass = (avg_sal - expected_avg).abs() < 0.01;
182 print_test("AVG produces mathematically correct result", test10_pass);
183 println!(" Average: ${:.2} (expected ${:.2})", avg_sal, expected_avg);
184
185 // TEST 11: MIN and MAX
186 println!("\nTest 11: MIN and MAX aggregations");
187 println!("SQL: SELECT MIN(salary), MAX(salary) FROM employees;");
188
189 let min_sal = Query::new(&employees).min_float(Employee::salary_r()).unwrap_or(0.0);
190 let max_sal = Query::new(&employees).max_float(Employee::salary_r()).unwrap_or(0.0);
191
192 let test11_pass = min_sal == 71000.0 && max_sal == 105000.0;
193 print_test("MIN and MAX produce correct results", test11_pass);
194 println!(" MIN: ${:.2}, MAX: ${:.2}", min_sal, max_sal);
195
196 // TEST 12: Complex WHERE with AND/OR
197 println!("\nTest 12: Complex WHERE (AND + OR)");
198 println!("SQL: SELECT * FROM employees WHERE (department = 'Engineering' OR department = 'Sales') AND salary > 80000;");
199
200 let complex_query = Query::new(&employees)
201 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
202 .where_(Employee::salary_r(), |&sal| sal > 80000.0);
203 let complex = complex_query.all();
204
205 let test12_pass = complex.len() == 4; // Alice J ($95k), Bob ($87k), David ($82k), Alice C ($105k)
206 print_test("Complex WHERE clause works correctly", test12_pass);
207 println!(" Found {} employees", complex.len());
208
209 // TEST 13: Case-sensitive string comparison (SQL default)
210 println!("\nTest 13: Case-sensitive comparison (like SQL)");
211 println!("SQL: SELECT * FROM employees WHERE department = 'engineering'; -- should find 0");
212
213 let case_sensitive = Query::new(&employees)
214 .where_(Employee::department_r(), |dept| dept == "engineering") // lowercase
215 .count();
216
217 let test13_pass = case_sensitive == 0;
218 print_test("Case-sensitive comparison (SQL default)", test13_pass);
219 println!(" Found {} with lowercase 'engineering' (expected 0)", case_sensitive);
220
221 // TEST 14: Case-insensitive LIKE equivalent
222 println!("\nTest 14: Case-insensitive LIKE (ILIKE equivalent)");
223 println!("SQL: SELECT * FROM employees WHERE LOWER(name) LIKE '%alice%';");
224
225 let ilike_query = Query::new(&employees)
226 .where_(Employee::name_r(), |name| name.to_lowercase().contains("alice"));
227 let ilike = ilike_query.all();
228
229 let test14_pass = ilike.len() == 2;
230 print_test("Case-insensitive LIKE works correctly", test14_pass);
231 println!(" Found {} employees with 'alice' (case-insensitive)", ilike.len());
232
233 // TEST 15: LIMIT produces exact subset
234 println!("\nTest 15: LIMIT clause");
235 println!("SQL: SELECT * FROM employees ORDER BY salary DESC LIMIT 3;");
236
237 let limited = Query::new(&employees)
238 .order_by_float_desc(Employee::salary_r())
239 .into_iter()
240 .take(3)
241 .collect::<Vec<_>>();
242
243 let test15_pass = limited.len() == 3
244 && limited[0].salary == 105000.0
245 && limited[1].salary == 95000.0
246 && limited[2].salary == 87000.0;
247 print_test("LIMIT returns correct top-N results", test15_pass);
248 println!(" Top 3 salaries: ${:.0}, ${:.0}, ${:.0}",
249 limited[0].salary, limited[1].salary, limited[2].salary);
250
251 // TEST 16: GROUP BY produces correct groups
252 println!("\nTest 16: GROUP BY");
253 println!("SQL: SELECT department, COUNT(*) FROM employees GROUP BY department;");
254
255 let grouped = Query::new(&employees).group_by(Employee::department_r());
256 let eng_count = grouped.get("Engineering").map(|v| v.len()).unwrap_or(0);
257 let sales_count = grouped.get("Sales").map(|v| v.len()).unwrap_or(0);
258 let marketing_count = grouped.get("Marketing").map(|v| v.len()).unwrap_or(0);
259
260 let test16_pass = eng_count == 3 && sales_count == 2 && marketing_count == 1;
261 print_test("GROUP BY produces correct counts", test16_pass);
262 println!(" Engineering: {}, Sales: {}, Marketing: {}", eng_count, sales_count, marketing_count);
263
264 // TEST 17: Email pattern matching (regex-like)
265 println!("\nTest 17: Email domain filtering (LIKE '%@example.com')");
266 println!("SQL: SELECT * FROM employees WHERE email LIKE '%@example.com';");
267
268 let example_emails = Query::new(&employees)
269 .where_(Employee::email_r(), |email| email.ends_with("@example.com"))
270 .count();
271
272 let test17_pass = example_emails == 6; // All employees have @example.com emails
273 print_test("Email pattern matching works correctly", test17_pass);
274 println!(" Found {} employees with @example.com emails", example_emails);
275
276 // Summary
277 println!("\n╔════════════════════════════════════════════════════════════════╗");
278 println!("║ Test Summary ║");
279 println!("╚════════════════════════════════════════════════════════════════╝\n");
280
281 let tests = vec![
282 ("ORDER BY DESC", test1_pass),
283 ("ORDER BY ASC", test2_pass),
284 ("ORDER BY name", test3_pass),
285 ("LIKE 'prefix%'", test4_pass),
286 ("LIKE '%suffix'", test5_pass),
287 ("LIKE '%contains%'", test6_pass),
288 ("IN clause", test7_pass),
289 ("BETWEEN clause", test8_pass),
290 ("COUNT", test9_pass),
291 ("AVG accuracy", test10_pass),
292 ("MIN/MAX", test11_pass),
293 ("Complex WHERE", test12_pass),
294 ("Case-sensitive", test13_pass),
295 ("Case-insensitive", test14_pass),
296 ("LIMIT", test15_pass),
297 ("GROUP BY", test16_pass),
298 ("Email patterns", test17_pass),
299 ];
300
301 let passed = tests.iter().filter(|(_, p)| *p).count();
302 let total = tests.len();
303
304 println!("Results: {}/{} tests passed", passed, total);
305
306 if passed == total {
307 println!("\n🎉 All tests PASSED! Rust Query Builder produces exact SQL-equivalent results!");
308 println!("\n✅ Verified:");
309 println!(" • Exact ordering (ASC/DESC)");
310 println!(" • LIKE operations (starts_with, ends_with, contains)");
311 println!(" • IN clause (OR conditions)");
312 println!(" • BETWEEN clause");
313 println!(" • Aggregations (COUNT, AVG, MIN, MAX)");
314 println!(" • Complex WHERE conditions");
315 println!(" • Case sensitivity");
316 println!(" • LIMIT clause");
317 println!(" • GROUP BY");
318 println!(" • Pattern matching");
319 } else {
320 println!("\n⚠️ {} test(s) failed. See details above.", total - passed);
321 }
322}Sourcepub fn all(&self) -> Vec<&T>
pub fn all(&self) -> Vec<&T>
Examples found in repository?
27fn main() {
28 println!("Individual Crates Example");
29 println!("=========================\n");
30 println!("Using rust-queries-core + rust-queries-derive directly\n");
31
32 let products = vec![
33 Product {
34 id: 1,
35 name: "Laptop".to_string(),
36 price: 999.99,
37 category: "Electronics".to_string(),
38 stock: 5,
39 },
40 Product {
41 id: 2,
42 name: "Mouse".to_string(),
43 price: 29.99,
44 category: "Electronics".to_string(),
45 stock: 50,
46 },
47 Product {
48 id: 3,
49 name: "Keyboard".to_string(),
50 price: 79.99,
51 category: "Electronics".to_string(),
52 stock: 30,
53 },
54 Product {
55 id: 4,
56 name: "Monitor".to_string(),
57 price: 299.99,
58 category: "Electronics".to_string(),
59 stock: 12,
60 },
61 Product {
62 id: 5,
63 name: "Desk Chair".to_string(),
64 price: 199.99,
65 category: "Furniture".to_string(),
66 stock: 8,
67 },
68 ];
69
70 println!("1. QueryExt from rust_queries_core");
71 println!(" products.query().where_(price > 100).all()");
72
73 let query = products
74 .query() // From QueryExt trait
75 .where_(Product::price_r(), |&p| p > 100.0);
76 let expensive = query.all();
77
78 println!(" Found {} expensive products:", expensive.len());
79 for product in expensive {
80 println!(" - {} (${:.2})", product.name, product.price);
81 }
82 println!();
83
84 println!("2. QueryBuilder from rust_queries_derive");
85 println!(" Product::query(&products).where_(stock < 10).all()");
86
87 let query2 = Product::query(&products) // From QueryBuilder derive
88 .where_(Product::stock_r(), |&s| s < 10);
89 let low_stock = query2.all();
90
91 println!(" Found {} low stock products:", low_stock.len());
92 for product in low_stock {
93 println!(" - {} (stock: {})", product.name, product.stock);
94 }
95 println!();
96
97 println!("3. LazyQuery from rust_queries_core");
98 println!(" products.lazy_query().where_(...).collect()");
99
100 let electronics: Vec<_> = products
101 .lazy_query() // From QueryExt trait
102 .where_(Product::category_r(), |cat| cat == "Electronics")
103 .collect();
104
105 println!(" Found {} electronics:", electronics.len());
106 for product in electronics {
107 println!(" - {}", product.name);
108 }
109 println!();
110
111 println!("4. Aggregations with LazyQuery");
112 println!(" products.lazy_query().sum_by(Product::price_r())");
113
114 let total_value: f64 = products
115 .lazy_query()
116 .sum_by(Product::price_r());
117
118 println!(" Total inventory value: ${:.2}", total_value);
119 println!();
120
121 println!("5. Early termination with lazy queries");
122 println!(" products.lazy_query().where_(...).first()");
123
124 if let Some(first_cheap) = products
125 .lazy_query()
126 .where_(Product::price_r(), |&p| p < 50.0)
127 .first()
128 {
129 println!(" First cheap product: {} (${:.2})", first_cheap.name, first_cheap.price);
130 }
131 println!();
132
133 println!("6. Using Query (eager) from rust_queries_core");
134 println!(" Query::new(&products).where_(...).count()");
135
136 let query3 = Query::new(&products) // Traditional approach
137 .where_(Product::price_r(), |&p| p > 50.0);
138 let count = query3.count();
139
140 println!(" Products over $50: {}", count);
141 println!();
142
143 println!("Summary:");
144 println!("--------");
145 println!("✓ rust_queries_core provides: Query, LazyQuery, QueryExt");
146 println!("✓ rust_queries_derive provides: #[derive(QueryBuilder)]");
147 println!("✓ key_paths_derive provides: #[derive(Keypaths)]");
148 println!("✓ All features work with individual crates!");
149}More examples
13fn main() {
14 println!("Derive Macros and Extension Traits Example");
15 println!("===========================================\n");
16
17 let products = vec![
18 Product {
19 id: 1,
20 name: "Laptop".to_string(),
21 price: 999.99,
22 category: "Electronics".to_string(),
23 stock: 5,
24 },
25 Product {
26 id: 2,
27 name: "Mouse".to_string(),
28 price: 29.99,
29 category: "Electronics".to_string(),
30 stock: 50,
31 },
32 Product {
33 id: 3,
34 name: "Keyboard".to_string(),
35 price: 79.99,
36 category: "Electronics".to_string(),
37 stock: 30,
38 },
39 Product {
40 id: 4,
41 name: "Monitor".to_string(),
42 price: 299.99,
43 category: "Electronics".to_string(),
44 stock: 12,
45 },
46 Product {
47 id: 5,
48 name: "Desk Chair".to_string(),
49 price: 199.99,
50 category: "Furniture".to_string(),
51 stock: 8,
52 },
53 ];
54
55 println!("1. Using Extension Trait - Direct .query() on Vec");
56 println!(" Query: products.query().where_(price > 100).all()");
57
58 let query = products
59 .query()
60 .where_(Product::price_r(), |&p| p > 100.0);
61 let expensive = query.all();
62
63 println!(" Found {} expensive products:", expensive.len());
64 for product in &expensive {
65 println!(" - {} (${:.2})", product.name, product.price);
66 }
67 println!();
68
69 println!("2. Using Extension Trait - Direct .lazy_query() on Vec");
70 println!(" Query: products.lazy_query().where_(stock < 10).collect()");
71
72 let low_stock: Vec<_> = products
73 .lazy_query()
74 .where_(Product::stock_r(), |&s| s < 10)
75 .collect();
76
77 println!(" Found {} low stock products:", low_stock.len());
78 for product in &low_stock {
79 println!(" - {} (stock: {})", product.name, product.stock);
80 }
81 println!();
82
83 println!("3. Using Extension Trait - Chained Operations");
84 println!(" Query: products.lazy_query().where_(category == Electronics).take(2).select(name).collect()");
85
86 let names: Vec<String> = products
87 .lazy_query()
88 .where_(Product::category_r(), |cat| cat == "Electronics")
89 .take_lazy(2)
90 .select_lazy(Product::name_r())
91 .collect();
92
93 println!(" First 2 electronics:");
94 for name in &names {
95 println!(" - {}", name);
96 }
97 println!();
98
99 println!("4. Using QueryBuilder Derive - Static Methods");
100 println!(" Query: Product::query(&products).where_(price > 50).count()");
101
102 let query4 = Product::query(&products)
103 .where_(Product::price_r(), |&p| p > 50.0);
104 let count = query4.count();
105
106 println!(" Products over $50: {}", count);
107 println!();
108
109 println!("5. Using QueryBuilder Derive - Lazy Static Methods");
110 println!(" Query: Product::lazy_query(&products).first()");
111
112 if let Some(first) = Product::lazy_query(&products).first() {
113 println!(" First product: {} (${:.2})", first.name, first.price);
114 }
115 println!();
116
117 println!("6. Complex Chain with Extension Trait");
118 println!(" Query: products.lazy_query()");
119 println!(" .where_(category == Electronics)");
120 println!(" .where_(price < 500)");
121 println!(" .map(|p| format!(\"{{}} - ${{:.2}}\", p.name, p.price))");
122 println!(" .collect()");
123
124 let formatted: Vec<String> = products
125 .lazy_query()
126 .where_(Product::category_r(), |cat| cat == "Electronics")
127 .where_(Product::price_r(), |&p| p < 500.0)
128 .map_items(|p| format!("{} - ${:.2}", p.name, p.price))
129 .collect();
130
131 println!(" Affordable electronics:");
132 for item in &formatted {
133 println!(" - {}", item);
134 }
135 println!();
136
137 println!("7. Aggregation with Extension Trait");
138 println!(" Query: products.lazy_query().sum_by(Product::stock())");
139
140 let total_stock = products
141 .lazy_query()
142 .sum_by(Product::stock_r());
143
144 println!(" Total stock across all products: {}", total_stock);
145 println!();
146
147 println!("8. Find with Extension Trait");
148 println!(" Query: products.lazy_query().find(|p| p.name.contains(\"Chair\"))");
149
150 if let Some(chair) = products.lazy_query().find(|p| p.name.contains("Chair")) {
151 println!(" Found: {} in {}", chair.name, chair.category);
152 }
153 println!();
154
155 println!("9. Early Termination with Extension Trait");
156 println!(" Query: products.lazy_query().where_(price > 1000).any()");
157
158 let has_luxury = products
159 .lazy_query()
160 .where_(Product::price_r(), |&p| p > 1000.0)
161 .any();
162
163 println!(" Has products over $1000: {}", has_luxury);
164 println!();
165
166 println!("10. Slice Extension Trait");
167 println!(" Query: (&products[..]).lazy_query().count()");
168
169 let slice_count = (&products[..])
170 .lazy_query()
171 .count();
172
173 println!(" Count from slice: {}", slice_count);
174 println!();
175
176 println!("Summary:");
177 println!("--------");
178 println!("✓ Extension trait QueryExt adds .query() and .lazy_query() to containers");
179 println!("✓ Derive macro QueryBuilder adds static methods Product::query() and Product::lazy_query()");
180 println!("✓ Both approaches provide the same query functionality");
181 println!("✓ Extension trait is more ergonomic: products.query() vs Query::new(&products)");
182 println!("✓ All iterator optimizations (fusion, early termination) still apply");
183}28fn main() {
29 println!("╔════════════════════════════════════════════════════════════╗");
30 println!("║ Query Builder Without Clone - Performance Optimization ║");
31 println!("╚════════════════════════════════════════════════════════════╝\n");
32
33 let employees = vec![
34 Employee {
35 id: 1,
36 name: "Alice".to_string(),
37 email: "alice@example.com".to_string(),
38 department: "Engineering".to_string(),
39 salary: 95000.0,
40 large_data: vec![0; 1000], // Large data - expensive to clone!
41 },
42 Employee {
43 id: 2,
44 name: "Bob".to_string(),
45 email: "bob@example.com".to_string(),
46 department: "Engineering".to_string(),
47 salary: 87000.0,
48 large_data: vec![0; 1000],
49 },
50 Employee {
51 id: 3,
52 name: "Carol".to_string(),
53 email: "carol@example.com".to_string(),
54 department: "Sales".to_string(),
55 salary: 75000.0,
56 large_data: vec![0; 1000],
57 },
58 ];
59
60 let departments = vec![
61 Department {
62 id: 1,
63 name: "Engineering".to_string(),
64 budget: 1000000.0,
65 },
66 Department {
67 id: 2,
68 name: "Sales".to_string(),
69 budget: 500000.0,
70 },
71 ];
72
73 println!("✅ Operations that DON'T require Clone:\n");
74
75 // 1. WHERE filtering - returns Vec<&T>
76 println!("1. WHERE filtering (returns references)");
77 let query = Query::new(&employees)
78 .where_(Employee::department_r(), |dept| dept == "Engineering");
79 let engineering = query.all();
80 println!(" Found {} engineering employees", engineering.len());
81 for emp in &engineering {
82 println!(" - {}: ${:.0}", emp.name, emp.salary);
83 }
84
85 // 2. COUNT - no cloning needed
86 println!("\n2. COUNT aggregation");
87 let count = Query::new(&employees)
88 .where_(Employee::salary_r(), |&sal| sal > 80000.0)
89 .count();
90 println!(" {} employees earn over $80k", count);
91
92 // 3. SELECT - only clones the selected field
93 println!("\n3. SELECT (only selected fields are cloned)");
94 let names: Vec<String> = Query::new(&employees)
95 .select(Employee::name_r());
96 println!(" Employee names: {:?}", names);
97
98 // 4. FIRST - returns Option<&T>
99 println!("\n4. FIRST (returns reference)");
100 let query = Query::new(&employees)
101 .where_(Employee::salary_r(), |&sal| sal > 90000.0);
102 if let Some(emp) = query.first() {
103 println!(" First high earner: {} (${:.0})", emp.name, emp.salary);
104 }
105
106 // 5. SUM/AVG aggregations - no cloning
107 println!("\n5. Aggregations (SUM/AVG)");
108 let eng_query = Query::new(&employees)
109 .where_(Employee::department_r(), |dept| dept == "Engineering");
110 let total = eng_query.sum(Employee::salary_r());
111 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
112 println!(" Engineering total: ${:.0}", total);
113 println!(" Engineering average: ${:.0}", avg);
114
115 // 6. MIN/MAX - no cloning
116 println!("\n6. MIN/MAX");
117 let min = Query::new(&employees).min_float(Employee::salary_r());
118 let max = Query::new(&employees).max_float(Employee::salary_r());
119 println!(" Salary range: ${:.0} - ${:.0}", min.unwrap(), max.unwrap());
120
121 // 7. LIMIT - returns Vec<&T>
122 println!("\n7. LIMIT (returns references)");
123 let query = Query::new(&employees);
124 let first_two = query.limit(2);
125 println!(" First 2 employees:");
126 for emp in &first_two {
127 println!(" - {}", emp.name);
128 }
129
130 // 8. SKIP/Pagination - returns Vec<&T>
131 println!("\n8. SKIP/Pagination (returns references)");
132 let query = Query::new(&employees);
133 let page_2 = query.skip(2).limit(1);
134 println!(" Page 2:");
135 for emp in &page_2 {
136 println!(" - {}", emp.name);
137 }
138
139 // 9. EXISTS - just checks
140 println!("\n9. EXISTS check");
141 let has_sales = Query::new(&employees)
142 .where_(Employee::department_r(), |dept| dept == "Sales")
143 .exists();
144 println!(" Has Sales employees: {}", has_sales);
145
146 // 10. JOIN - no Clone required on L or R!
147 println!("\n10. JOIN operations (no Clone required!)");
148 let results = JoinQuery::new(&employees, &departments)
149 .inner_join(
150 Employee::department_r(),
151 Department::name_r(),
152 |emp, dept| {
153 // Mapper only clones what it needs for the result
154 (emp.name.clone(), dept.budget)
155 },
156 );
157 println!(" Employee-Department pairs:");
158 for (name, budget) in &results {
159 println!(" - {} works in dept with ${:.0} budget", name, budget);
160 }
161
162 println!("\n╔════════════════════════════════════════════════════════════╗");
163 println!("║ Operations that REQUIRE Clone (only when needed) ║");
164 println!("╚════════════════════════════════════════════════════════════╝\n");
165
166 println!("⚠️ The following operations require Clone because they return owned Vec<T>:");
167 println!(" - order_by() / order_by_desc()");
168 println!(" - order_by_float() / order_by_float_desc()");
169 println!(" - group_by()");
170 println!("\n To use these, add #[derive(Clone)] to your struct:");
171 println!(" ```rust");
172 println!(" #[derive(Clone, Keypaths)] // Add Clone here");
173 println!(" struct Employee {{ ... }}");
174 println!(" ```");
175
176 println!("\n╔════════════════════════════════════════════════════════════╗");
177 println!("║ Performance Benefits ║");
178 println!("╚════════════════════════════════════════════════════════════╝\n");
179
180 println!("✅ Zero cloning for most operations");
181 println!("✅ Work with large structs efficiently");
182 println!("✅ No unnecessary memory allocations");
183 println!("✅ Only clone when you actually need owned data");
184 println!("✅ Pay for what you use");
185
186 println!("\n✓ Example complete! Most operations work without Clone.\n");
187}30fn main() {
31 println!("Testing documentation examples...\n");
32
33 // Example from README - Quick Start
34 println!("Test 1: README Quick Start Example");
35 {
36 let products = vec![
37 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
38 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
39 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
40 ];
41
42 let affordable_query = Query::new(&products)
43 .where_(Product::category_r(), |cat| cat == "Electronics")
44 .where_(Product::price_r(), |&price| price < 100.0);
45 let affordable_electronics = affordable_query.all();
46
47 println!(" Found {} affordable electronics ✅", affordable_electronics.len());
48 }
49
50 // Example from README - Filtering
51 println!("\nTest 2: Filtering Example");
52 {
53 let products = vec![
54 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
55 ];
56
57 let electronics_query = Query::new(&products)
58 .where_(Product::category_r(), |cat| cat == "Electronics");
59 let electronics = electronics_query.all();
60
61 println!(" Found {} electronics ✅", electronics.len());
62 }
63
64 // Example from README - Selecting
65 println!("\nTest 3: Selecting Fields Example");
66 {
67 let products = vec![
68 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
69 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
70 ];
71
72 let names: Vec<String> = Query::new(&products)
73 .select(Product::name_r());
74
75 println!(" Selected {} names ✅", names.len());
76 }
77
78 // Example from README - Ordering
79 println!("\nTest 4: Ordering Example");
80 {
81 let products = vec![
82 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
83 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
84 ];
85
86 let by_price = Query::new(&products).order_by_float(Product::price_r());
87 println!(" Ordered {} products ✅", by_price.len());
88 }
89
90 // Example from README - Aggregations
91 println!("\nTest 5: Aggregations Example");
92 {
93 let products = vec![
94 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
95 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
96 ];
97
98 let electronics_query = Query::new(&products)
99 .where_(Product::category_r(), |cat| cat == "Electronics");
100
101 let count = electronics_query.count();
102 let total_value: f64 = electronics_query.sum(Product::price_r());
103 let avg_price = electronics_query.avg(Product::price_r()).unwrap_or(0.0);
104
105 println!(" Count: {}, Total: ${:.2}, Avg: ${:.2} ✅", count, total_value, avg_price);
106 }
107
108 // Example from README - Grouping
109 println!("\nTest 6: Grouping Example");
110 {
111 let products = vec![
112 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
113 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
114 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
115 ];
116
117 let by_category = Query::new(&products).group_by(Product::category_r());
118 println!(" Grouped into {} categories ✅", by_category.len());
119 }
120
121 // Example from README - Pagination
122 println!("\nTest 7: Pagination Example");
123 {
124 let products = vec![
125 Product { id: 1, name: "P1".to_string(), price: 10.0, category: "A".to_string(), stock: 1, rating: 4.0 },
126 Product { id: 2, name: "P2".to_string(), price: 20.0, category: "A".to_string(), stock: 1, rating: 4.0 },
127 Product { id: 3, name: "P3".to_string(), price: 30.0, category: "A".to_string(), stock: 1, rating: 4.0 },
128 ];
129
130 let query = Query::new(&products);
131 let first_10 = query.limit(10);
132 let page_1 = query.skip(0).limit(10);
133
134 println!(" Limited to {} products ✅", first_10.len());
135 println!(" Page 1 has {} products ✅", page_1.len());
136 }
137
138 // Example from README - Join
139 println!("\nTest 8: Join Example");
140 {
141 let users = vec![
142 User { id: 1, name: "Alice".to_string() },
143 User { id: 2, name: "Bob".to_string() },
144 ];
145
146 let orders = vec![
147 Order { id: 101, user_id: 1, total: 99.99 },
148 Order { id: 102, user_id: 1, total: 149.99 },
149 ];
150
151 let user_orders = JoinQuery::new(&users, &orders).inner_join(
152 User::id_r(),
153 Order::user_id_r(),
154 |user, order| (user.name.clone(), order.total),
155 );
156
157 println!(" Joined {} user-order pairs ✅", user_orders.len());
158 }
159
160 // Example from SQL_COMPARISON - SELECT with WHERE
161 println!("\nTest 9: SQL Comparison - SELECT with WHERE");
162 {
163 #[derive(Clone, Keypaths)]
164 struct Employee {
165 department: String,
166 }
167
168 let employees = vec![
169 Employee { department: "Engineering".to_string() },
170 Employee { department: "Sales".to_string() },
171 ];
172
173 let engineering_query = Query::new(&employees)
174 .where_(Employee::department_r(), |dept| dept == "Engineering");
175 let engineering = engineering_query.all();
176
177 println!(" Found {} engineering employees ✅", engineering.len());
178 }
179
180 // Example from USAGE.md - Complex Filtering
181 println!("\nTest 10: USAGE - Complex Filtering");
182 {
183 let products = vec![
184 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
185 ];
186
187 let results_query = Query::new(&products)
188 .where_(Product::category_r(), |cat| cat == "Electronics")
189 .where_(Product::price_r(), |&price| price >= 100.0 && price <= 500.0)
190 .where_(Product::stock_r(), |&stock| stock > 10);
191 let results = results_query.order_by_float(Product::price_r());
192
193 println!(" Filtered {} products ✅", results.len());
194 }
195
196 println!("\n✅ All documentation examples compile and run successfully!");
197}110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}33fn main() {
34 let employees = create_test_data();
35
36 println!("\n╔════════════════════════════════════════════════════════════════╗");
37 println!("║ SQL Equivalence Verification Tests ║");
38 println!("╚════════════════════════════════════════════════════════════════╝\n");
39
40 // TEST 1: ORDER BY maintains exact SQL ordering (DESC)
41 println!("Test 1: ORDER BY DESC - Exact ordering");
42 println!("SQL: SELECT * FROM employees ORDER BY salary DESC;");
43
44 let ordered = Query::new(&employees).order_by_float_desc(Employee::salary_r());
45 let expected_order = vec![105000.0, 95000.0, 87000.0, 82000.0, 75000.0, 71000.0];
46 let actual_order: Vec<f64> = ordered.iter().map(|e| e.salary).collect();
47
48 let test1_pass = expected_order == actual_order;
49 print_test("ORDER BY salary DESC produces correct order", test1_pass);
50 if !test1_pass {
51 println!(" Expected: {:?}", expected_order);
52 println!(" Got: {:?}", actual_order);
53 }
54
55 // TEST 2: ORDER BY maintains exact SQL ordering (ASC)
56 println!("\nTest 2: ORDER BY ASC - Exact ordering");
57 println!("SQL: SELECT * FROM employees ORDER BY salary ASC;");
58
59 let ordered_asc = Query::new(&employees).order_by_float(Employee::salary_r());
60 let expected_asc = vec![71000.0, 75000.0, 82000.0, 87000.0, 95000.0, 105000.0];
61 let actual_asc: Vec<f64> = ordered_asc.iter().map(|e| e.salary).collect();
62
63 let test2_pass = expected_asc == actual_asc;
64 print_test("ORDER BY salary ASC produces correct order", test2_pass);
65 if !test2_pass {
66 println!(" Expected: {:?}", expected_asc);
67 println!(" Got: {:?}", actual_asc);
68 }
69
70 // TEST 3: String ordering (alphabetical)
71 println!("\nTest 3: ORDER BY name (alphabetical)");
72 println!("SQL: SELECT name FROM employees ORDER BY name;");
73
74 let ordered_names = Query::new(&employees).order_by(Employee::name_r());
75 let expected_names = vec!["Alice Cooper", "Alice Johnson", "Bob Smith", "Carol White", "David Brown", "Eve Davis"];
76 let actual_names: Vec<&str> = ordered_names.iter().map(|e| e.name.as_str()).collect();
77
78 let test3_pass = expected_names == actual_names;
79 print_test("ORDER BY name produces correct alphabetical order", test3_pass);
80 if !test3_pass {
81 println!(" Expected: {:?}", expected_names);
82 println!(" Got: {:?}", actual_names);
83 }
84
85 // TEST 4: LIKE equivalent - starts with
86 println!("\nTest 4: LIKE 'Alice%' equivalent");
87 println!("SQL: SELECT * FROM employees WHERE name LIKE 'Alice%';");
88
89 let like_alice_query = Query::new(&employees)
90 .where_(Employee::name_r(), |name| name.starts_with("Alice"));
91 let like_alice = like_alice_query.all();
92
93 let test4_pass = like_alice.len() == 2
94 && like_alice.iter().all(|e| e.name.starts_with("Alice"));
95 print_test("LIKE 'Alice%' (starts_with) works correctly", test4_pass);
96 if test4_pass {
97 for emp in &like_alice {
98 println!(" Found: {}", emp.name);
99 }
100 }
101
102 // TEST 5: LIKE equivalent - ends with
103 println!("\nTest 5: LIKE '%son' equivalent");
104 println!("SQL: SELECT * FROM employees WHERE name LIKE '%son';");
105
106 let like_son_query = Query::new(&employees)
107 .where_(Employee::name_r(), |name| name.ends_with("son"));
108 let like_son = like_son_query.all();
109
110 let test5_pass = like_son.len() == 1 && like_son[0].name == "Alice Johnson";
111 print_test("LIKE '%son' (ends_with) works correctly", test5_pass);
112 if test5_pass {
113 for emp in &like_son {
114 println!(" Found: {}", emp.name);
115 }
116 }
117
118 // TEST 6: LIKE equivalent - contains
119 println!("\nTest 6: LIKE '%mit%' equivalent");
120 println!("SQL: SELECT * FROM employees WHERE name LIKE '%mit%';");
121
122 let like_mit_query = Query::new(&employees)
123 .where_(Employee::name_r(), |name| name.contains("mit"));
124 let like_mit = like_mit_query.all();
125
126 let test6_pass = like_mit.len() == 1 && like_mit[0].name == "Bob Smith";
127 print_test("LIKE '%mit%' (contains) works correctly", test6_pass);
128 if test6_pass {
129 for emp in &like_mit {
130 println!(" Found: {}", emp.name);
131 }
132 }
133
134 // TEST 7: IN clause equivalent
135 println!("\nTest 7: IN clause equivalent");
136 println!("SQL: SELECT * FROM employees WHERE department IN ('Engineering', 'Sales');");
137
138 let in_depts_query = Query::new(&employees)
139 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales");
140 let in_depts = in_depts_query.all();
141
142 let test7_pass = in_depts.len() == 5 // 3 Engineering + 2 Sales
143 && in_depts.iter().all(|e| e.department == "Engineering" || e.department == "Sales");
144 print_test("IN clause works correctly", test7_pass);
145 println!(" Found {} employees in Engineering or Sales", in_depts.len());
146
147 // TEST 8: BETWEEN equivalent
148 println!("\nTest 8: BETWEEN clause equivalent");
149 println!("SQL: SELECT * FROM employees WHERE salary BETWEEN 75000 AND 90000;");
150
151 let between_query = Query::new(&employees)
152 .where_(Employee::salary_r(), |&sal| sal >= 75000.0 && sal <= 90000.0);
153 let between = between_query.all();
154
155 let test8_pass = between.len() == 3;
156 print_test("BETWEEN clause works correctly", test8_pass);
157 println!(" Found {} employees with salary between 75K-90K", between.len());
158
159 // TEST 9: COUNT with WHERE
160 println!("\nTest 9: COUNT with WHERE");
161 println!("SQL: SELECT COUNT(*) FROM employees WHERE department = 'Engineering';");
162
163 let count_eng = Query::new(&employees)
164 .where_(Employee::department_r(), |dept| dept == "Engineering")
165 .count();
166
167 let test9_pass = count_eng == 3;
168 print_test("COUNT with WHERE produces correct result", test9_pass);
169 println!(" Count: {} (expected 3)", count_eng);
170
171 // TEST 10: AVG produces exact result
172 println!("\nTest 10: AVG aggregation accuracy");
173 println!("SQL: SELECT AVG(salary) FROM employees WHERE department = 'Engineering';");
174
175 let avg_sal = Query::new(&employees)
176 .where_(Employee::department_r(), |dept| dept == "Engineering")
177 .avg(Employee::salary_r())
178 .unwrap_or(0.0);
179
180 let expected_avg = (95000.0 + 87000.0 + 105000.0) / 3.0;
181 let test10_pass = (avg_sal - expected_avg).abs() < 0.01;
182 print_test("AVG produces mathematically correct result", test10_pass);
183 println!(" Average: ${:.2} (expected ${:.2})", avg_sal, expected_avg);
184
185 // TEST 11: MIN and MAX
186 println!("\nTest 11: MIN and MAX aggregations");
187 println!("SQL: SELECT MIN(salary), MAX(salary) FROM employees;");
188
189 let min_sal = Query::new(&employees).min_float(Employee::salary_r()).unwrap_or(0.0);
190 let max_sal = Query::new(&employees).max_float(Employee::salary_r()).unwrap_or(0.0);
191
192 let test11_pass = min_sal == 71000.0 && max_sal == 105000.0;
193 print_test("MIN and MAX produce correct results", test11_pass);
194 println!(" MIN: ${:.2}, MAX: ${:.2}", min_sal, max_sal);
195
196 // TEST 12: Complex WHERE with AND/OR
197 println!("\nTest 12: Complex WHERE (AND + OR)");
198 println!("SQL: SELECT * FROM employees WHERE (department = 'Engineering' OR department = 'Sales') AND salary > 80000;");
199
200 let complex_query = Query::new(&employees)
201 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
202 .where_(Employee::salary_r(), |&sal| sal > 80000.0);
203 let complex = complex_query.all();
204
205 let test12_pass = complex.len() == 4; // Alice J ($95k), Bob ($87k), David ($82k), Alice C ($105k)
206 print_test("Complex WHERE clause works correctly", test12_pass);
207 println!(" Found {} employees", complex.len());
208
209 // TEST 13: Case-sensitive string comparison (SQL default)
210 println!("\nTest 13: Case-sensitive comparison (like SQL)");
211 println!("SQL: SELECT * FROM employees WHERE department = 'engineering'; -- should find 0");
212
213 let case_sensitive = Query::new(&employees)
214 .where_(Employee::department_r(), |dept| dept == "engineering") // lowercase
215 .count();
216
217 let test13_pass = case_sensitive == 0;
218 print_test("Case-sensitive comparison (SQL default)", test13_pass);
219 println!(" Found {} with lowercase 'engineering' (expected 0)", case_sensitive);
220
221 // TEST 14: Case-insensitive LIKE equivalent
222 println!("\nTest 14: Case-insensitive LIKE (ILIKE equivalent)");
223 println!("SQL: SELECT * FROM employees WHERE LOWER(name) LIKE '%alice%';");
224
225 let ilike_query = Query::new(&employees)
226 .where_(Employee::name_r(), |name| name.to_lowercase().contains("alice"));
227 let ilike = ilike_query.all();
228
229 let test14_pass = ilike.len() == 2;
230 print_test("Case-insensitive LIKE works correctly", test14_pass);
231 println!(" Found {} employees with 'alice' (case-insensitive)", ilike.len());
232
233 // TEST 15: LIMIT produces exact subset
234 println!("\nTest 15: LIMIT clause");
235 println!("SQL: SELECT * FROM employees ORDER BY salary DESC LIMIT 3;");
236
237 let limited = Query::new(&employees)
238 .order_by_float_desc(Employee::salary_r())
239 .into_iter()
240 .take(3)
241 .collect::<Vec<_>>();
242
243 let test15_pass = limited.len() == 3
244 && limited[0].salary == 105000.0
245 && limited[1].salary == 95000.0
246 && limited[2].salary == 87000.0;
247 print_test("LIMIT returns correct top-N results", test15_pass);
248 println!(" Top 3 salaries: ${:.0}, ${:.0}, ${:.0}",
249 limited[0].salary, limited[1].salary, limited[2].salary);
250
251 // TEST 16: GROUP BY produces correct groups
252 println!("\nTest 16: GROUP BY");
253 println!("SQL: SELECT department, COUNT(*) FROM employees GROUP BY department;");
254
255 let grouped = Query::new(&employees).group_by(Employee::department_r());
256 let eng_count = grouped.get("Engineering").map(|v| v.len()).unwrap_or(0);
257 let sales_count = grouped.get("Sales").map(|v| v.len()).unwrap_or(0);
258 let marketing_count = grouped.get("Marketing").map(|v| v.len()).unwrap_or(0);
259
260 let test16_pass = eng_count == 3 && sales_count == 2 && marketing_count == 1;
261 print_test("GROUP BY produces correct counts", test16_pass);
262 println!(" Engineering: {}, Sales: {}, Marketing: {}", eng_count, sales_count, marketing_count);
263
264 // TEST 17: Email pattern matching (regex-like)
265 println!("\nTest 17: Email domain filtering (LIKE '%@example.com')");
266 println!("SQL: SELECT * FROM employees WHERE email LIKE '%@example.com';");
267
268 let example_emails = Query::new(&employees)
269 .where_(Employee::email_r(), |email| email.ends_with("@example.com"))
270 .count();
271
272 let test17_pass = example_emails == 6; // All employees have @example.com emails
273 print_test("Email pattern matching works correctly", test17_pass);
274 println!(" Found {} employees with @example.com emails", example_emails);
275
276 // Summary
277 println!("\n╔════════════════════════════════════════════════════════════════╗");
278 println!("║ Test Summary ║");
279 println!("╚════════════════════════════════════════════════════════════════╝\n");
280
281 let tests = vec![
282 ("ORDER BY DESC", test1_pass),
283 ("ORDER BY ASC", test2_pass),
284 ("ORDER BY name", test3_pass),
285 ("LIKE 'prefix%'", test4_pass),
286 ("LIKE '%suffix'", test5_pass),
287 ("LIKE '%contains%'", test6_pass),
288 ("IN clause", test7_pass),
289 ("BETWEEN clause", test8_pass),
290 ("COUNT", test9_pass),
291 ("AVG accuracy", test10_pass),
292 ("MIN/MAX", test11_pass),
293 ("Complex WHERE", test12_pass),
294 ("Case-sensitive", test13_pass),
295 ("Case-insensitive", test14_pass),
296 ("LIMIT", test15_pass),
297 ("GROUP BY", test16_pass),
298 ("Email patterns", test17_pass),
299 ];
300
301 let passed = tests.iter().filter(|(_, p)| *p).count();
302 let total = tests.len();
303
304 println!("Results: {}/{} tests passed", passed, total);
305
306 if passed == total {
307 println!("\n🎉 All tests PASSED! Rust Query Builder produces exact SQL-equivalent results!");
308 println!("\n✅ Verified:");
309 println!(" • Exact ordering (ASC/DESC)");
310 println!(" • LIKE operations (starts_with, ends_with, contains)");
311 println!(" • IN clause (OR conditions)");
312 println!(" • BETWEEN clause");
313 println!(" • Aggregations (COUNT, AVG, MIN, MAX)");
314 println!(" • Complex WHERE conditions");
315 println!(" • Case sensitivity");
316 println!(" • LIMIT clause");
317 println!(" • GROUP BY");
318 println!(" • Pattern matching");
319 } else {
320 println!("\n⚠️ {} test(s) failed. See details above.", total - passed);
321 }
322}Sourcepub fn first(&self) -> Option<&T>
pub fn first(&self) -> Option<&T>
Examples found in repository?
28fn main() {
29 println!("╔════════════════════════════════════════════════════════════╗");
30 println!("║ Query Builder Without Clone - Performance Optimization ║");
31 println!("╚════════════════════════════════════════════════════════════╝\n");
32
33 let employees = vec![
34 Employee {
35 id: 1,
36 name: "Alice".to_string(),
37 email: "alice@example.com".to_string(),
38 department: "Engineering".to_string(),
39 salary: 95000.0,
40 large_data: vec![0; 1000], // Large data - expensive to clone!
41 },
42 Employee {
43 id: 2,
44 name: "Bob".to_string(),
45 email: "bob@example.com".to_string(),
46 department: "Engineering".to_string(),
47 salary: 87000.0,
48 large_data: vec![0; 1000],
49 },
50 Employee {
51 id: 3,
52 name: "Carol".to_string(),
53 email: "carol@example.com".to_string(),
54 department: "Sales".to_string(),
55 salary: 75000.0,
56 large_data: vec![0; 1000],
57 },
58 ];
59
60 let departments = vec![
61 Department {
62 id: 1,
63 name: "Engineering".to_string(),
64 budget: 1000000.0,
65 },
66 Department {
67 id: 2,
68 name: "Sales".to_string(),
69 budget: 500000.0,
70 },
71 ];
72
73 println!("✅ Operations that DON'T require Clone:\n");
74
75 // 1. WHERE filtering - returns Vec<&T>
76 println!("1. WHERE filtering (returns references)");
77 let query = Query::new(&employees)
78 .where_(Employee::department_r(), |dept| dept == "Engineering");
79 let engineering = query.all();
80 println!(" Found {} engineering employees", engineering.len());
81 for emp in &engineering {
82 println!(" - {}: ${:.0}", emp.name, emp.salary);
83 }
84
85 // 2. COUNT - no cloning needed
86 println!("\n2. COUNT aggregation");
87 let count = Query::new(&employees)
88 .where_(Employee::salary_r(), |&sal| sal > 80000.0)
89 .count();
90 println!(" {} employees earn over $80k", count);
91
92 // 3. SELECT - only clones the selected field
93 println!("\n3. SELECT (only selected fields are cloned)");
94 let names: Vec<String> = Query::new(&employees)
95 .select(Employee::name_r());
96 println!(" Employee names: {:?}", names);
97
98 // 4. FIRST - returns Option<&T>
99 println!("\n4. FIRST (returns reference)");
100 let query = Query::new(&employees)
101 .where_(Employee::salary_r(), |&sal| sal > 90000.0);
102 if let Some(emp) = query.first() {
103 println!(" First high earner: {} (${:.0})", emp.name, emp.salary);
104 }
105
106 // 5. SUM/AVG aggregations - no cloning
107 println!("\n5. Aggregations (SUM/AVG)");
108 let eng_query = Query::new(&employees)
109 .where_(Employee::department_r(), |dept| dept == "Engineering");
110 let total = eng_query.sum(Employee::salary_r());
111 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
112 println!(" Engineering total: ${:.0}", total);
113 println!(" Engineering average: ${:.0}", avg);
114
115 // 6. MIN/MAX - no cloning
116 println!("\n6. MIN/MAX");
117 let min = Query::new(&employees).min_float(Employee::salary_r());
118 let max = Query::new(&employees).max_float(Employee::salary_r());
119 println!(" Salary range: ${:.0} - ${:.0}", min.unwrap(), max.unwrap());
120
121 // 7. LIMIT - returns Vec<&T>
122 println!("\n7. LIMIT (returns references)");
123 let query = Query::new(&employees);
124 let first_two = query.limit(2);
125 println!(" First 2 employees:");
126 for emp in &first_two {
127 println!(" - {}", emp.name);
128 }
129
130 // 8. SKIP/Pagination - returns Vec<&T>
131 println!("\n8. SKIP/Pagination (returns references)");
132 let query = Query::new(&employees);
133 let page_2 = query.skip(2).limit(1);
134 println!(" Page 2:");
135 for emp in &page_2 {
136 println!(" - {}", emp.name);
137 }
138
139 // 9. EXISTS - just checks
140 println!("\n9. EXISTS check");
141 let has_sales = Query::new(&employees)
142 .where_(Employee::department_r(), |dept| dept == "Sales")
143 .exists();
144 println!(" Has Sales employees: {}", has_sales);
145
146 // 10. JOIN - no Clone required on L or R!
147 println!("\n10. JOIN operations (no Clone required!)");
148 let results = JoinQuery::new(&employees, &departments)
149 .inner_join(
150 Employee::department_r(),
151 Department::name_r(),
152 |emp, dept| {
153 // Mapper only clones what it needs for the result
154 (emp.name.clone(), dept.budget)
155 },
156 );
157 println!(" Employee-Department pairs:");
158 for (name, budget) in &results {
159 println!(" - {} works in dept with ${:.0} budget", name, budget);
160 }
161
162 println!("\n╔════════════════════════════════════════════════════════════╗");
163 println!("║ Operations that REQUIRE Clone (only when needed) ║");
164 println!("╚════════════════════════════════════════════════════════════╝\n");
165
166 println!("⚠️ The following operations require Clone because they return owned Vec<T>:");
167 println!(" - order_by() / order_by_desc()");
168 println!(" - order_by_float() / order_by_float_desc()");
169 println!(" - group_by()");
170 println!("\n To use these, add #[derive(Clone)] to your struct:");
171 println!(" ```rust");
172 println!(" #[derive(Clone, Keypaths)] // Add Clone here");
173 println!(" struct Employee {{ ... }}");
174 println!(" ```");
175
176 println!("\n╔════════════════════════════════════════════════════════════╗");
177 println!("║ Performance Benefits ║");
178 println!("╚════════════════════════════════════════════════════════════╝\n");
179
180 println!("✅ Zero cloning for most operations");
181 println!("✅ Work with large structs efficiently");
182 println!("✅ No unnecessary memory allocations");
183 println!("✅ Only clone when you actually need owned data");
184 println!("✅ Pay for what you use");
185
186 println!("\n✓ Example complete! Most operations work without Clone.\n");
187}More examples
110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}Sourcepub fn count(&self) -> usize
pub fn count(&self) -> usize
Examples found in repository?
27fn main() {
28 println!("Individual Crates Example");
29 println!("=========================\n");
30 println!("Using rust-queries-core + rust-queries-derive directly\n");
31
32 let products = vec![
33 Product {
34 id: 1,
35 name: "Laptop".to_string(),
36 price: 999.99,
37 category: "Electronics".to_string(),
38 stock: 5,
39 },
40 Product {
41 id: 2,
42 name: "Mouse".to_string(),
43 price: 29.99,
44 category: "Electronics".to_string(),
45 stock: 50,
46 },
47 Product {
48 id: 3,
49 name: "Keyboard".to_string(),
50 price: 79.99,
51 category: "Electronics".to_string(),
52 stock: 30,
53 },
54 Product {
55 id: 4,
56 name: "Monitor".to_string(),
57 price: 299.99,
58 category: "Electronics".to_string(),
59 stock: 12,
60 },
61 Product {
62 id: 5,
63 name: "Desk Chair".to_string(),
64 price: 199.99,
65 category: "Furniture".to_string(),
66 stock: 8,
67 },
68 ];
69
70 println!("1. QueryExt from rust_queries_core");
71 println!(" products.query().where_(price > 100).all()");
72
73 let query = products
74 .query() // From QueryExt trait
75 .where_(Product::price_r(), |&p| p > 100.0);
76 let expensive = query.all();
77
78 println!(" Found {} expensive products:", expensive.len());
79 for product in expensive {
80 println!(" - {} (${:.2})", product.name, product.price);
81 }
82 println!();
83
84 println!("2. QueryBuilder from rust_queries_derive");
85 println!(" Product::query(&products).where_(stock < 10).all()");
86
87 let query2 = Product::query(&products) // From QueryBuilder derive
88 .where_(Product::stock_r(), |&s| s < 10);
89 let low_stock = query2.all();
90
91 println!(" Found {} low stock products:", low_stock.len());
92 for product in low_stock {
93 println!(" - {} (stock: {})", product.name, product.stock);
94 }
95 println!();
96
97 println!("3. LazyQuery from rust_queries_core");
98 println!(" products.lazy_query().where_(...).collect()");
99
100 let electronics: Vec<_> = products
101 .lazy_query() // From QueryExt trait
102 .where_(Product::category_r(), |cat| cat == "Electronics")
103 .collect();
104
105 println!(" Found {} electronics:", electronics.len());
106 for product in electronics {
107 println!(" - {}", product.name);
108 }
109 println!();
110
111 println!("4. Aggregations with LazyQuery");
112 println!(" products.lazy_query().sum_by(Product::price_r())");
113
114 let total_value: f64 = products
115 .lazy_query()
116 .sum_by(Product::price_r());
117
118 println!(" Total inventory value: ${:.2}", total_value);
119 println!();
120
121 println!("5. Early termination with lazy queries");
122 println!(" products.lazy_query().where_(...).first()");
123
124 if let Some(first_cheap) = products
125 .lazy_query()
126 .where_(Product::price_r(), |&p| p < 50.0)
127 .first()
128 {
129 println!(" First cheap product: {} (${:.2})", first_cheap.name, first_cheap.price);
130 }
131 println!();
132
133 println!("6. Using Query (eager) from rust_queries_core");
134 println!(" Query::new(&products).where_(...).count()");
135
136 let query3 = Query::new(&products) // Traditional approach
137 .where_(Product::price_r(), |&p| p > 50.0);
138 let count = query3.count();
139
140 println!(" Products over $50: {}", count);
141 println!();
142
143 println!("Summary:");
144 println!("--------");
145 println!("✓ rust_queries_core provides: Query, LazyQuery, QueryExt");
146 println!("✓ rust_queries_derive provides: #[derive(QueryBuilder)]");
147 println!("✓ key_paths_derive provides: #[derive(Keypaths)]");
148 println!("✓ All features work with individual crates!");
149}More examples
13fn main() {
14 println!("Derive Macros and Extension Traits Example");
15 println!("===========================================\n");
16
17 let products = vec![
18 Product {
19 id: 1,
20 name: "Laptop".to_string(),
21 price: 999.99,
22 category: "Electronics".to_string(),
23 stock: 5,
24 },
25 Product {
26 id: 2,
27 name: "Mouse".to_string(),
28 price: 29.99,
29 category: "Electronics".to_string(),
30 stock: 50,
31 },
32 Product {
33 id: 3,
34 name: "Keyboard".to_string(),
35 price: 79.99,
36 category: "Electronics".to_string(),
37 stock: 30,
38 },
39 Product {
40 id: 4,
41 name: "Monitor".to_string(),
42 price: 299.99,
43 category: "Electronics".to_string(),
44 stock: 12,
45 },
46 Product {
47 id: 5,
48 name: "Desk Chair".to_string(),
49 price: 199.99,
50 category: "Furniture".to_string(),
51 stock: 8,
52 },
53 ];
54
55 println!("1. Using Extension Trait - Direct .query() on Vec");
56 println!(" Query: products.query().where_(price > 100).all()");
57
58 let query = products
59 .query()
60 .where_(Product::price_r(), |&p| p > 100.0);
61 let expensive = query.all();
62
63 println!(" Found {} expensive products:", expensive.len());
64 for product in &expensive {
65 println!(" - {} (${:.2})", product.name, product.price);
66 }
67 println!();
68
69 println!("2. Using Extension Trait - Direct .lazy_query() on Vec");
70 println!(" Query: products.lazy_query().where_(stock < 10).collect()");
71
72 let low_stock: Vec<_> = products
73 .lazy_query()
74 .where_(Product::stock_r(), |&s| s < 10)
75 .collect();
76
77 println!(" Found {} low stock products:", low_stock.len());
78 for product in &low_stock {
79 println!(" - {} (stock: {})", product.name, product.stock);
80 }
81 println!();
82
83 println!("3. Using Extension Trait - Chained Operations");
84 println!(" Query: products.lazy_query().where_(category == Electronics).take(2).select(name).collect()");
85
86 let names: Vec<String> = products
87 .lazy_query()
88 .where_(Product::category_r(), |cat| cat == "Electronics")
89 .take_lazy(2)
90 .select_lazy(Product::name_r())
91 .collect();
92
93 println!(" First 2 electronics:");
94 for name in &names {
95 println!(" - {}", name);
96 }
97 println!();
98
99 println!("4. Using QueryBuilder Derive - Static Methods");
100 println!(" Query: Product::query(&products).where_(price > 50).count()");
101
102 let query4 = Product::query(&products)
103 .where_(Product::price_r(), |&p| p > 50.0);
104 let count = query4.count();
105
106 println!(" Products over $50: {}", count);
107 println!();
108
109 println!("5. Using QueryBuilder Derive - Lazy Static Methods");
110 println!(" Query: Product::lazy_query(&products).first()");
111
112 if let Some(first) = Product::lazy_query(&products).first() {
113 println!(" First product: {} (${:.2})", first.name, first.price);
114 }
115 println!();
116
117 println!("6. Complex Chain with Extension Trait");
118 println!(" Query: products.lazy_query()");
119 println!(" .where_(category == Electronics)");
120 println!(" .where_(price < 500)");
121 println!(" .map(|p| format!(\"{{}} - ${{:.2}}\", p.name, p.price))");
122 println!(" .collect()");
123
124 let formatted: Vec<String> = products
125 .lazy_query()
126 .where_(Product::category_r(), |cat| cat == "Electronics")
127 .where_(Product::price_r(), |&p| p < 500.0)
128 .map_items(|p| format!("{} - ${:.2}", p.name, p.price))
129 .collect();
130
131 println!(" Affordable electronics:");
132 for item in &formatted {
133 println!(" - {}", item);
134 }
135 println!();
136
137 println!("7. Aggregation with Extension Trait");
138 println!(" Query: products.lazy_query().sum_by(Product::stock())");
139
140 let total_stock = products
141 .lazy_query()
142 .sum_by(Product::stock_r());
143
144 println!(" Total stock across all products: {}", total_stock);
145 println!();
146
147 println!("8. Find with Extension Trait");
148 println!(" Query: products.lazy_query().find(|p| p.name.contains(\"Chair\"))");
149
150 if let Some(chair) = products.lazy_query().find(|p| p.name.contains("Chair")) {
151 println!(" Found: {} in {}", chair.name, chair.category);
152 }
153 println!();
154
155 println!("9. Early Termination with Extension Trait");
156 println!(" Query: products.lazy_query().where_(price > 1000).any()");
157
158 let has_luxury = products
159 .lazy_query()
160 .where_(Product::price_r(), |&p| p > 1000.0)
161 .any();
162
163 println!(" Has products over $1000: {}", has_luxury);
164 println!();
165
166 println!("10. Slice Extension Trait");
167 println!(" Query: (&products[..]).lazy_query().count()");
168
169 let slice_count = (&products[..])
170 .lazy_query()
171 .count();
172
173 println!(" Count from slice: {}", slice_count);
174 println!();
175
176 println!("Summary:");
177 println!("--------");
178 println!("✓ Extension trait QueryExt adds .query() and .lazy_query() to containers");
179 println!("✓ Derive macro QueryBuilder adds static methods Product::query() and Product::lazy_query()");
180 println!("✓ Both approaches provide the same query functionality");
181 println!("✓ Extension trait is more ergonomic: products.query() vs Query::new(&products)");
182 println!("✓ All iterator optimizations (fusion, early termination) still apply");
183}28fn main() {
29 println!("╔════════════════════════════════════════════════════════════╗");
30 println!("║ Query Builder Without Clone - Performance Optimization ║");
31 println!("╚════════════════════════════════════════════════════════════╝\n");
32
33 let employees = vec![
34 Employee {
35 id: 1,
36 name: "Alice".to_string(),
37 email: "alice@example.com".to_string(),
38 department: "Engineering".to_string(),
39 salary: 95000.0,
40 large_data: vec![0; 1000], // Large data - expensive to clone!
41 },
42 Employee {
43 id: 2,
44 name: "Bob".to_string(),
45 email: "bob@example.com".to_string(),
46 department: "Engineering".to_string(),
47 salary: 87000.0,
48 large_data: vec![0; 1000],
49 },
50 Employee {
51 id: 3,
52 name: "Carol".to_string(),
53 email: "carol@example.com".to_string(),
54 department: "Sales".to_string(),
55 salary: 75000.0,
56 large_data: vec![0; 1000],
57 },
58 ];
59
60 let departments = vec![
61 Department {
62 id: 1,
63 name: "Engineering".to_string(),
64 budget: 1000000.0,
65 },
66 Department {
67 id: 2,
68 name: "Sales".to_string(),
69 budget: 500000.0,
70 },
71 ];
72
73 println!("✅ Operations that DON'T require Clone:\n");
74
75 // 1. WHERE filtering - returns Vec<&T>
76 println!("1. WHERE filtering (returns references)");
77 let query = Query::new(&employees)
78 .where_(Employee::department_r(), |dept| dept == "Engineering");
79 let engineering = query.all();
80 println!(" Found {} engineering employees", engineering.len());
81 for emp in &engineering {
82 println!(" - {}: ${:.0}", emp.name, emp.salary);
83 }
84
85 // 2. COUNT - no cloning needed
86 println!("\n2. COUNT aggregation");
87 let count = Query::new(&employees)
88 .where_(Employee::salary_r(), |&sal| sal > 80000.0)
89 .count();
90 println!(" {} employees earn over $80k", count);
91
92 // 3. SELECT - only clones the selected field
93 println!("\n3. SELECT (only selected fields are cloned)");
94 let names: Vec<String> = Query::new(&employees)
95 .select(Employee::name_r());
96 println!(" Employee names: {:?}", names);
97
98 // 4. FIRST - returns Option<&T>
99 println!("\n4. FIRST (returns reference)");
100 let query = Query::new(&employees)
101 .where_(Employee::salary_r(), |&sal| sal > 90000.0);
102 if let Some(emp) = query.first() {
103 println!(" First high earner: {} (${:.0})", emp.name, emp.salary);
104 }
105
106 // 5. SUM/AVG aggregations - no cloning
107 println!("\n5. Aggregations (SUM/AVG)");
108 let eng_query = Query::new(&employees)
109 .where_(Employee::department_r(), |dept| dept == "Engineering");
110 let total = eng_query.sum(Employee::salary_r());
111 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
112 println!(" Engineering total: ${:.0}", total);
113 println!(" Engineering average: ${:.0}", avg);
114
115 // 6. MIN/MAX - no cloning
116 println!("\n6. MIN/MAX");
117 let min = Query::new(&employees).min_float(Employee::salary_r());
118 let max = Query::new(&employees).max_float(Employee::salary_r());
119 println!(" Salary range: ${:.0} - ${:.0}", min.unwrap(), max.unwrap());
120
121 // 7. LIMIT - returns Vec<&T>
122 println!("\n7. LIMIT (returns references)");
123 let query = Query::new(&employees);
124 let first_two = query.limit(2);
125 println!(" First 2 employees:");
126 for emp in &first_two {
127 println!(" - {}", emp.name);
128 }
129
130 // 8. SKIP/Pagination - returns Vec<&T>
131 println!("\n8. SKIP/Pagination (returns references)");
132 let query = Query::new(&employees);
133 let page_2 = query.skip(2).limit(1);
134 println!(" Page 2:");
135 for emp in &page_2 {
136 println!(" - {}", emp.name);
137 }
138
139 // 9. EXISTS - just checks
140 println!("\n9. EXISTS check");
141 let has_sales = Query::new(&employees)
142 .where_(Employee::department_r(), |dept| dept == "Sales")
143 .exists();
144 println!(" Has Sales employees: {}", has_sales);
145
146 // 10. JOIN - no Clone required on L or R!
147 println!("\n10. JOIN operations (no Clone required!)");
148 let results = JoinQuery::new(&employees, &departments)
149 .inner_join(
150 Employee::department_r(),
151 Department::name_r(),
152 |emp, dept| {
153 // Mapper only clones what it needs for the result
154 (emp.name.clone(), dept.budget)
155 },
156 );
157 println!(" Employee-Department pairs:");
158 for (name, budget) in &results {
159 println!(" - {} works in dept with ${:.0} budget", name, budget);
160 }
161
162 println!("\n╔════════════════════════════════════════════════════════════╗");
163 println!("║ Operations that REQUIRE Clone (only when needed) ║");
164 println!("╚════════════════════════════════════════════════════════════╝\n");
165
166 println!("⚠️ The following operations require Clone because they return owned Vec<T>:");
167 println!(" - order_by() / order_by_desc()");
168 println!(" - order_by_float() / order_by_float_desc()");
169 println!(" - group_by()");
170 println!("\n To use these, add #[derive(Clone)] to your struct:");
171 println!(" ```rust");
172 println!(" #[derive(Clone, Keypaths)] // Add Clone here");
173 println!(" struct Employee {{ ... }}");
174 println!(" ```");
175
176 println!("\n╔════════════════════════════════════════════════════════════╗");
177 println!("║ Performance Benefits ║");
178 println!("╚════════════════════════════════════════════════════════════╝\n");
179
180 println!("✅ Zero cloning for most operations");
181 println!("✅ Work with large structs efficiently");
182 println!("✅ No unnecessary memory allocations");
183 println!("✅ Only clone when you actually need owned data");
184 println!("✅ Pay for what you use");
185
186 println!("\n✓ Example complete! Most operations work without Clone.\n");
187}30fn main() {
31 println!("Testing documentation examples...\n");
32
33 // Example from README - Quick Start
34 println!("Test 1: README Quick Start Example");
35 {
36 let products = vec![
37 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
38 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
39 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
40 ];
41
42 let affordable_query = Query::new(&products)
43 .where_(Product::category_r(), |cat| cat == "Electronics")
44 .where_(Product::price_r(), |&price| price < 100.0);
45 let affordable_electronics = affordable_query.all();
46
47 println!(" Found {} affordable electronics ✅", affordable_electronics.len());
48 }
49
50 // Example from README - Filtering
51 println!("\nTest 2: Filtering Example");
52 {
53 let products = vec![
54 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
55 ];
56
57 let electronics_query = Query::new(&products)
58 .where_(Product::category_r(), |cat| cat == "Electronics");
59 let electronics = electronics_query.all();
60
61 println!(" Found {} electronics ✅", electronics.len());
62 }
63
64 // Example from README - Selecting
65 println!("\nTest 3: Selecting Fields Example");
66 {
67 let products = vec![
68 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
69 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
70 ];
71
72 let names: Vec<String> = Query::new(&products)
73 .select(Product::name_r());
74
75 println!(" Selected {} names ✅", names.len());
76 }
77
78 // Example from README - Ordering
79 println!("\nTest 4: Ordering Example");
80 {
81 let products = vec![
82 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
83 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
84 ];
85
86 let by_price = Query::new(&products).order_by_float(Product::price_r());
87 println!(" Ordered {} products ✅", by_price.len());
88 }
89
90 // Example from README - Aggregations
91 println!("\nTest 5: Aggregations Example");
92 {
93 let products = vec![
94 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
95 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
96 ];
97
98 let electronics_query = Query::new(&products)
99 .where_(Product::category_r(), |cat| cat == "Electronics");
100
101 let count = electronics_query.count();
102 let total_value: f64 = electronics_query.sum(Product::price_r());
103 let avg_price = electronics_query.avg(Product::price_r()).unwrap_or(0.0);
104
105 println!(" Count: {}, Total: ${:.2}, Avg: ${:.2} ✅", count, total_value, avg_price);
106 }
107
108 // Example from README - Grouping
109 println!("\nTest 6: Grouping Example");
110 {
111 let products = vec![
112 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
113 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
114 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
115 ];
116
117 let by_category = Query::new(&products).group_by(Product::category_r());
118 println!(" Grouped into {} categories ✅", by_category.len());
119 }
120
121 // Example from README - Pagination
122 println!("\nTest 7: Pagination Example");
123 {
124 let products = vec![
125 Product { id: 1, name: "P1".to_string(), price: 10.0, category: "A".to_string(), stock: 1, rating: 4.0 },
126 Product { id: 2, name: "P2".to_string(), price: 20.0, category: "A".to_string(), stock: 1, rating: 4.0 },
127 Product { id: 3, name: "P3".to_string(), price: 30.0, category: "A".to_string(), stock: 1, rating: 4.0 },
128 ];
129
130 let query = Query::new(&products);
131 let first_10 = query.limit(10);
132 let page_1 = query.skip(0).limit(10);
133
134 println!(" Limited to {} products ✅", first_10.len());
135 println!(" Page 1 has {} products ✅", page_1.len());
136 }
137
138 // Example from README - Join
139 println!("\nTest 8: Join Example");
140 {
141 let users = vec![
142 User { id: 1, name: "Alice".to_string() },
143 User { id: 2, name: "Bob".to_string() },
144 ];
145
146 let orders = vec![
147 Order { id: 101, user_id: 1, total: 99.99 },
148 Order { id: 102, user_id: 1, total: 149.99 },
149 ];
150
151 let user_orders = JoinQuery::new(&users, &orders).inner_join(
152 User::id_r(),
153 Order::user_id_r(),
154 |user, order| (user.name.clone(), order.total),
155 );
156
157 println!(" Joined {} user-order pairs ✅", user_orders.len());
158 }
159
160 // Example from SQL_COMPARISON - SELECT with WHERE
161 println!("\nTest 9: SQL Comparison - SELECT with WHERE");
162 {
163 #[derive(Clone, Keypaths)]
164 struct Employee {
165 department: String,
166 }
167
168 let employees = vec![
169 Employee { department: "Engineering".to_string() },
170 Employee { department: "Sales".to_string() },
171 ];
172
173 let engineering_query = Query::new(&employees)
174 .where_(Employee::department_r(), |dept| dept == "Engineering");
175 let engineering = engineering_query.all();
176
177 println!(" Found {} engineering employees ✅", engineering.len());
178 }
179
180 // Example from USAGE.md - Complex Filtering
181 println!("\nTest 10: USAGE - Complex Filtering");
182 {
183 let products = vec![
184 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
185 ];
186
187 let results_query = Query::new(&products)
188 .where_(Product::category_r(), |cat| cat == "Electronics")
189 .where_(Product::price_r(), |&price| price >= 100.0 && price <= 500.0)
190 .where_(Product::stock_r(), |&stock| stock > 10);
191 let results = results_query.order_by_float(Product::price_r());
192
193 println!(" Filtered {} products ✅", results.len());
194 }
195
196 println!("\n✅ All documentation examples compile and run successfully!");
197}110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}33fn main() {
34 let employees = create_test_data();
35
36 println!("\n╔════════════════════════════════════════════════════════════════╗");
37 println!("║ SQL Equivalence Verification Tests ║");
38 println!("╚════════════════════════════════════════════════════════════════╝\n");
39
40 // TEST 1: ORDER BY maintains exact SQL ordering (DESC)
41 println!("Test 1: ORDER BY DESC - Exact ordering");
42 println!("SQL: SELECT * FROM employees ORDER BY salary DESC;");
43
44 let ordered = Query::new(&employees).order_by_float_desc(Employee::salary_r());
45 let expected_order = vec![105000.0, 95000.0, 87000.0, 82000.0, 75000.0, 71000.0];
46 let actual_order: Vec<f64> = ordered.iter().map(|e| e.salary).collect();
47
48 let test1_pass = expected_order == actual_order;
49 print_test("ORDER BY salary DESC produces correct order", test1_pass);
50 if !test1_pass {
51 println!(" Expected: {:?}", expected_order);
52 println!(" Got: {:?}", actual_order);
53 }
54
55 // TEST 2: ORDER BY maintains exact SQL ordering (ASC)
56 println!("\nTest 2: ORDER BY ASC - Exact ordering");
57 println!("SQL: SELECT * FROM employees ORDER BY salary ASC;");
58
59 let ordered_asc = Query::new(&employees).order_by_float(Employee::salary_r());
60 let expected_asc = vec![71000.0, 75000.0, 82000.0, 87000.0, 95000.0, 105000.0];
61 let actual_asc: Vec<f64> = ordered_asc.iter().map(|e| e.salary).collect();
62
63 let test2_pass = expected_asc == actual_asc;
64 print_test("ORDER BY salary ASC produces correct order", test2_pass);
65 if !test2_pass {
66 println!(" Expected: {:?}", expected_asc);
67 println!(" Got: {:?}", actual_asc);
68 }
69
70 // TEST 3: String ordering (alphabetical)
71 println!("\nTest 3: ORDER BY name (alphabetical)");
72 println!("SQL: SELECT name FROM employees ORDER BY name;");
73
74 let ordered_names = Query::new(&employees).order_by(Employee::name_r());
75 let expected_names = vec!["Alice Cooper", "Alice Johnson", "Bob Smith", "Carol White", "David Brown", "Eve Davis"];
76 let actual_names: Vec<&str> = ordered_names.iter().map(|e| e.name.as_str()).collect();
77
78 let test3_pass = expected_names == actual_names;
79 print_test("ORDER BY name produces correct alphabetical order", test3_pass);
80 if !test3_pass {
81 println!(" Expected: {:?}", expected_names);
82 println!(" Got: {:?}", actual_names);
83 }
84
85 // TEST 4: LIKE equivalent - starts with
86 println!("\nTest 4: LIKE 'Alice%' equivalent");
87 println!("SQL: SELECT * FROM employees WHERE name LIKE 'Alice%';");
88
89 let like_alice_query = Query::new(&employees)
90 .where_(Employee::name_r(), |name| name.starts_with("Alice"));
91 let like_alice = like_alice_query.all();
92
93 let test4_pass = like_alice.len() == 2
94 && like_alice.iter().all(|e| e.name.starts_with("Alice"));
95 print_test("LIKE 'Alice%' (starts_with) works correctly", test4_pass);
96 if test4_pass {
97 for emp in &like_alice {
98 println!(" Found: {}", emp.name);
99 }
100 }
101
102 // TEST 5: LIKE equivalent - ends with
103 println!("\nTest 5: LIKE '%son' equivalent");
104 println!("SQL: SELECT * FROM employees WHERE name LIKE '%son';");
105
106 let like_son_query = Query::new(&employees)
107 .where_(Employee::name_r(), |name| name.ends_with("son"));
108 let like_son = like_son_query.all();
109
110 let test5_pass = like_son.len() == 1 && like_son[0].name == "Alice Johnson";
111 print_test("LIKE '%son' (ends_with) works correctly", test5_pass);
112 if test5_pass {
113 for emp in &like_son {
114 println!(" Found: {}", emp.name);
115 }
116 }
117
118 // TEST 6: LIKE equivalent - contains
119 println!("\nTest 6: LIKE '%mit%' equivalent");
120 println!("SQL: SELECT * FROM employees WHERE name LIKE '%mit%';");
121
122 let like_mit_query = Query::new(&employees)
123 .where_(Employee::name_r(), |name| name.contains("mit"));
124 let like_mit = like_mit_query.all();
125
126 let test6_pass = like_mit.len() == 1 && like_mit[0].name == "Bob Smith";
127 print_test("LIKE '%mit%' (contains) works correctly", test6_pass);
128 if test6_pass {
129 for emp in &like_mit {
130 println!(" Found: {}", emp.name);
131 }
132 }
133
134 // TEST 7: IN clause equivalent
135 println!("\nTest 7: IN clause equivalent");
136 println!("SQL: SELECT * FROM employees WHERE department IN ('Engineering', 'Sales');");
137
138 let in_depts_query = Query::new(&employees)
139 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales");
140 let in_depts = in_depts_query.all();
141
142 let test7_pass = in_depts.len() == 5 // 3 Engineering + 2 Sales
143 && in_depts.iter().all(|e| e.department == "Engineering" || e.department == "Sales");
144 print_test("IN clause works correctly", test7_pass);
145 println!(" Found {} employees in Engineering or Sales", in_depts.len());
146
147 // TEST 8: BETWEEN equivalent
148 println!("\nTest 8: BETWEEN clause equivalent");
149 println!("SQL: SELECT * FROM employees WHERE salary BETWEEN 75000 AND 90000;");
150
151 let between_query = Query::new(&employees)
152 .where_(Employee::salary_r(), |&sal| sal >= 75000.0 && sal <= 90000.0);
153 let between = between_query.all();
154
155 let test8_pass = between.len() == 3;
156 print_test("BETWEEN clause works correctly", test8_pass);
157 println!(" Found {} employees with salary between 75K-90K", between.len());
158
159 // TEST 9: COUNT with WHERE
160 println!("\nTest 9: COUNT with WHERE");
161 println!("SQL: SELECT COUNT(*) FROM employees WHERE department = 'Engineering';");
162
163 let count_eng = Query::new(&employees)
164 .where_(Employee::department_r(), |dept| dept == "Engineering")
165 .count();
166
167 let test9_pass = count_eng == 3;
168 print_test("COUNT with WHERE produces correct result", test9_pass);
169 println!(" Count: {} (expected 3)", count_eng);
170
171 // TEST 10: AVG produces exact result
172 println!("\nTest 10: AVG aggregation accuracy");
173 println!("SQL: SELECT AVG(salary) FROM employees WHERE department = 'Engineering';");
174
175 let avg_sal = Query::new(&employees)
176 .where_(Employee::department_r(), |dept| dept == "Engineering")
177 .avg(Employee::salary_r())
178 .unwrap_or(0.0);
179
180 let expected_avg = (95000.0 + 87000.0 + 105000.0) / 3.0;
181 let test10_pass = (avg_sal - expected_avg).abs() < 0.01;
182 print_test("AVG produces mathematically correct result", test10_pass);
183 println!(" Average: ${:.2} (expected ${:.2})", avg_sal, expected_avg);
184
185 // TEST 11: MIN and MAX
186 println!("\nTest 11: MIN and MAX aggregations");
187 println!("SQL: SELECT MIN(salary), MAX(salary) FROM employees;");
188
189 let min_sal = Query::new(&employees).min_float(Employee::salary_r()).unwrap_or(0.0);
190 let max_sal = Query::new(&employees).max_float(Employee::salary_r()).unwrap_or(0.0);
191
192 let test11_pass = min_sal == 71000.0 && max_sal == 105000.0;
193 print_test("MIN and MAX produce correct results", test11_pass);
194 println!(" MIN: ${:.2}, MAX: ${:.2}", min_sal, max_sal);
195
196 // TEST 12: Complex WHERE with AND/OR
197 println!("\nTest 12: Complex WHERE (AND + OR)");
198 println!("SQL: SELECT * FROM employees WHERE (department = 'Engineering' OR department = 'Sales') AND salary > 80000;");
199
200 let complex_query = Query::new(&employees)
201 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
202 .where_(Employee::salary_r(), |&sal| sal > 80000.0);
203 let complex = complex_query.all();
204
205 let test12_pass = complex.len() == 4; // Alice J ($95k), Bob ($87k), David ($82k), Alice C ($105k)
206 print_test("Complex WHERE clause works correctly", test12_pass);
207 println!(" Found {} employees", complex.len());
208
209 // TEST 13: Case-sensitive string comparison (SQL default)
210 println!("\nTest 13: Case-sensitive comparison (like SQL)");
211 println!("SQL: SELECT * FROM employees WHERE department = 'engineering'; -- should find 0");
212
213 let case_sensitive = Query::new(&employees)
214 .where_(Employee::department_r(), |dept| dept == "engineering") // lowercase
215 .count();
216
217 let test13_pass = case_sensitive == 0;
218 print_test("Case-sensitive comparison (SQL default)", test13_pass);
219 println!(" Found {} with lowercase 'engineering' (expected 0)", case_sensitive);
220
221 // TEST 14: Case-insensitive LIKE equivalent
222 println!("\nTest 14: Case-insensitive LIKE (ILIKE equivalent)");
223 println!("SQL: SELECT * FROM employees WHERE LOWER(name) LIKE '%alice%';");
224
225 let ilike_query = Query::new(&employees)
226 .where_(Employee::name_r(), |name| name.to_lowercase().contains("alice"));
227 let ilike = ilike_query.all();
228
229 let test14_pass = ilike.len() == 2;
230 print_test("Case-insensitive LIKE works correctly", test14_pass);
231 println!(" Found {} employees with 'alice' (case-insensitive)", ilike.len());
232
233 // TEST 15: LIMIT produces exact subset
234 println!("\nTest 15: LIMIT clause");
235 println!("SQL: SELECT * FROM employees ORDER BY salary DESC LIMIT 3;");
236
237 let limited = Query::new(&employees)
238 .order_by_float_desc(Employee::salary_r())
239 .into_iter()
240 .take(3)
241 .collect::<Vec<_>>();
242
243 let test15_pass = limited.len() == 3
244 && limited[0].salary == 105000.0
245 && limited[1].salary == 95000.0
246 && limited[2].salary == 87000.0;
247 print_test("LIMIT returns correct top-N results", test15_pass);
248 println!(" Top 3 salaries: ${:.0}, ${:.0}, ${:.0}",
249 limited[0].salary, limited[1].salary, limited[2].salary);
250
251 // TEST 16: GROUP BY produces correct groups
252 println!("\nTest 16: GROUP BY");
253 println!("SQL: SELECT department, COUNT(*) FROM employees GROUP BY department;");
254
255 let grouped = Query::new(&employees).group_by(Employee::department_r());
256 let eng_count = grouped.get("Engineering").map(|v| v.len()).unwrap_or(0);
257 let sales_count = grouped.get("Sales").map(|v| v.len()).unwrap_or(0);
258 let marketing_count = grouped.get("Marketing").map(|v| v.len()).unwrap_or(0);
259
260 let test16_pass = eng_count == 3 && sales_count == 2 && marketing_count == 1;
261 print_test("GROUP BY produces correct counts", test16_pass);
262 println!(" Engineering: {}, Sales: {}, Marketing: {}", eng_count, sales_count, marketing_count);
263
264 // TEST 17: Email pattern matching (regex-like)
265 println!("\nTest 17: Email domain filtering (LIKE '%@example.com')");
266 println!("SQL: SELECT * FROM employees WHERE email LIKE '%@example.com';");
267
268 let example_emails = Query::new(&employees)
269 .where_(Employee::email_r(), |email| email.ends_with("@example.com"))
270 .count();
271
272 let test17_pass = example_emails == 6; // All employees have @example.com emails
273 print_test("Email pattern matching works correctly", test17_pass);
274 println!(" Found {} employees with @example.com emails", example_emails);
275
276 // Summary
277 println!("\n╔════════════════════════════════════════════════════════════════╗");
278 println!("║ Test Summary ║");
279 println!("╚════════════════════════════════════════════════════════════════╝\n");
280
281 let tests = vec![
282 ("ORDER BY DESC", test1_pass),
283 ("ORDER BY ASC", test2_pass),
284 ("ORDER BY name", test3_pass),
285 ("LIKE 'prefix%'", test4_pass),
286 ("LIKE '%suffix'", test5_pass),
287 ("LIKE '%contains%'", test6_pass),
288 ("IN clause", test7_pass),
289 ("BETWEEN clause", test8_pass),
290 ("COUNT", test9_pass),
291 ("AVG accuracy", test10_pass),
292 ("MIN/MAX", test11_pass),
293 ("Complex WHERE", test12_pass),
294 ("Case-sensitive", test13_pass),
295 ("Case-insensitive", test14_pass),
296 ("LIMIT", test15_pass),
297 ("GROUP BY", test16_pass),
298 ("Email patterns", test17_pass),
299 ];
300
301 let passed = tests.iter().filter(|(_, p)| *p).count();
302 let total = tests.len();
303
304 println!("Results: {}/{} tests passed", passed, total);
305
306 if passed == total {
307 println!("\n🎉 All tests PASSED! Rust Query Builder produces exact SQL-equivalent results!");
308 println!("\n✅ Verified:");
309 println!(" • Exact ordering (ASC/DESC)");
310 println!(" • LIKE operations (starts_with, ends_with, contains)");
311 println!(" • IN clause (OR conditions)");
312 println!(" • BETWEEN clause");
313 println!(" • Aggregations (COUNT, AVG, MIN, MAX)");
314 println!(" • Complex WHERE conditions");
315 println!(" • Case sensitivity");
316 println!(" • LIMIT clause");
317 println!(" • GROUP BY");
318 println!(" • Pattern matching");
319 } else {
320 println!("\n⚠️ {} test(s) failed. See details above.", total - passed);
321 }
322}Sourcepub fn limit(&self, n: usize) -> Vec<&T>
pub fn limit(&self, n: usize) -> Vec<&T>
Returns the first n items matching the query filters.
§Arguments
n- The maximum number of items to return
§Example
let first_10 = query.limit(10);Examples found in repository?
28fn main() {
29 println!("╔════════════════════════════════════════════════════════════╗");
30 println!("║ Query Builder Without Clone - Performance Optimization ║");
31 println!("╚════════════════════════════════════════════════════════════╝\n");
32
33 let employees = vec![
34 Employee {
35 id: 1,
36 name: "Alice".to_string(),
37 email: "alice@example.com".to_string(),
38 department: "Engineering".to_string(),
39 salary: 95000.0,
40 large_data: vec![0; 1000], // Large data - expensive to clone!
41 },
42 Employee {
43 id: 2,
44 name: "Bob".to_string(),
45 email: "bob@example.com".to_string(),
46 department: "Engineering".to_string(),
47 salary: 87000.0,
48 large_data: vec![0; 1000],
49 },
50 Employee {
51 id: 3,
52 name: "Carol".to_string(),
53 email: "carol@example.com".to_string(),
54 department: "Sales".to_string(),
55 salary: 75000.0,
56 large_data: vec![0; 1000],
57 },
58 ];
59
60 let departments = vec![
61 Department {
62 id: 1,
63 name: "Engineering".to_string(),
64 budget: 1000000.0,
65 },
66 Department {
67 id: 2,
68 name: "Sales".to_string(),
69 budget: 500000.0,
70 },
71 ];
72
73 println!("✅ Operations that DON'T require Clone:\n");
74
75 // 1. WHERE filtering - returns Vec<&T>
76 println!("1. WHERE filtering (returns references)");
77 let query = Query::new(&employees)
78 .where_(Employee::department_r(), |dept| dept == "Engineering");
79 let engineering = query.all();
80 println!(" Found {} engineering employees", engineering.len());
81 for emp in &engineering {
82 println!(" - {}: ${:.0}", emp.name, emp.salary);
83 }
84
85 // 2. COUNT - no cloning needed
86 println!("\n2. COUNT aggregation");
87 let count = Query::new(&employees)
88 .where_(Employee::salary_r(), |&sal| sal > 80000.0)
89 .count();
90 println!(" {} employees earn over $80k", count);
91
92 // 3. SELECT - only clones the selected field
93 println!("\n3. SELECT (only selected fields are cloned)");
94 let names: Vec<String> = Query::new(&employees)
95 .select(Employee::name_r());
96 println!(" Employee names: {:?}", names);
97
98 // 4. FIRST - returns Option<&T>
99 println!("\n4. FIRST (returns reference)");
100 let query = Query::new(&employees)
101 .where_(Employee::salary_r(), |&sal| sal > 90000.0);
102 if let Some(emp) = query.first() {
103 println!(" First high earner: {} (${:.0})", emp.name, emp.salary);
104 }
105
106 // 5. SUM/AVG aggregations - no cloning
107 println!("\n5. Aggregations (SUM/AVG)");
108 let eng_query = Query::new(&employees)
109 .where_(Employee::department_r(), |dept| dept == "Engineering");
110 let total = eng_query.sum(Employee::salary_r());
111 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
112 println!(" Engineering total: ${:.0}", total);
113 println!(" Engineering average: ${:.0}", avg);
114
115 // 6. MIN/MAX - no cloning
116 println!("\n6. MIN/MAX");
117 let min = Query::new(&employees).min_float(Employee::salary_r());
118 let max = Query::new(&employees).max_float(Employee::salary_r());
119 println!(" Salary range: ${:.0} - ${:.0}", min.unwrap(), max.unwrap());
120
121 // 7. LIMIT - returns Vec<&T>
122 println!("\n7. LIMIT (returns references)");
123 let query = Query::new(&employees);
124 let first_two = query.limit(2);
125 println!(" First 2 employees:");
126 for emp in &first_two {
127 println!(" - {}", emp.name);
128 }
129
130 // 8. SKIP/Pagination - returns Vec<&T>
131 println!("\n8. SKIP/Pagination (returns references)");
132 let query = Query::new(&employees);
133 let page_2 = query.skip(2).limit(1);
134 println!(" Page 2:");
135 for emp in &page_2 {
136 println!(" - {}", emp.name);
137 }
138
139 // 9. EXISTS - just checks
140 println!("\n9. EXISTS check");
141 let has_sales = Query::new(&employees)
142 .where_(Employee::department_r(), |dept| dept == "Sales")
143 .exists();
144 println!(" Has Sales employees: {}", has_sales);
145
146 // 10. JOIN - no Clone required on L or R!
147 println!("\n10. JOIN operations (no Clone required!)");
148 let results = JoinQuery::new(&employees, &departments)
149 .inner_join(
150 Employee::department_r(),
151 Department::name_r(),
152 |emp, dept| {
153 // Mapper only clones what it needs for the result
154 (emp.name.clone(), dept.budget)
155 },
156 );
157 println!(" Employee-Department pairs:");
158 for (name, budget) in &results {
159 println!(" - {} works in dept with ${:.0} budget", name, budget);
160 }
161
162 println!("\n╔════════════════════════════════════════════════════════════╗");
163 println!("║ Operations that REQUIRE Clone (only when needed) ║");
164 println!("╚════════════════════════════════════════════════════════════╝\n");
165
166 println!("⚠️ The following operations require Clone because they return owned Vec<T>:");
167 println!(" - order_by() / order_by_desc()");
168 println!(" - order_by_float() / order_by_float_desc()");
169 println!(" - group_by()");
170 println!("\n To use these, add #[derive(Clone)] to your struct:");
171 println!(" ```rust");
172 println!(" #[derive(Clone, Keypaths)] // Add Clone here");
173 println!(" struct Employee {{ ... }}");
174 println!(" ```");
175
176 println!("\n╔════════════════════════════════════════════════════════════╗");
177 println!("║ Performance Benefits ║");
178 println!("╚════════════════════════════════════════════════════════════╝\n");
179
180 println!("✅ Zero cloning for most operations");
181 println!("✅ Work with large structs efficiently");
182 println!("✅ No unnecessary memory allocations");
183 println!("✅ Only clone when you actually need owned data");
184 println!("✅ Pay for what you use");
185
186 println!("\n✓ Example complete! Most operations work without Clone.\n");
187}More examples
30fn main() {
31 println!("Testing documentation examples...\n");
32
33 // Example from README - Quick Start
34 println!("Test 1: README Quick Start Example");
35 {
36 let products = vec![
37 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
38 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
39 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
40 ];
41
42 let affordable_query = Query::new(&products)
43 .where_(Product::category_r(), |cat| cat == "Electronics")
44 .where_(Product::price_r(), |&price| price < 100.0);
45 let affordable_electronics = affordable_query.all();
46
47 println!(" Found {} affordable electronics ✅", affordable_electronics.len());
48 }
49
50 // Example from README - Filtering
51 println!("\nTest 2: Filtering Example");
52 {
53 let products = vec![
54 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
55 ];
56
57 let electronics_query = Query::new(&products)
58 .where_(Product::category_r(), |cat| cat == "Electronics");
59 let electronics = electronics_query.all();
60
61 println!(" Found {} electronics ✅", electronics.len());
62 }
63
64 // Example from README - Selecting
65 println!("\nTest 3: Selecting Fields Example");
66 {
67 let products = vec![
68 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
69 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
70 ];
71
72 let names: Vec<String> = Query::new(&products)
73 .select(Product::name_r());
74
75 println!(" Selected {} names ✅", names.len());
76 }
77
78 // Example from README - Ordering
79 println!("\nTest 4: Ordering Example");
80 {
81 let products = vec![
82 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
83 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
84 ];
85
86 let by_price = Query::new(&products).order_by_float(Product::price_r());
87 println!(" Ordered {} products ✅", by_price.len());
88 }
89
90 // Example from README - Aggregations
91 println!("\nTest 5: Aggregations Example");
92 {
93 let products = vec![
94 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
95 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
96 ];
97
98 let electronics_query = Query::new(&products)
99 .where_(Product::category_r(), |cat| cat == "Electronics");
100
101 let count = electronics_query.count();
102 let total_value: f64 = electronics_query.sum(Product::price_r());
103 let avg_price = electronics_query.avg(Product::price_r()).unwrap_or(0.0);
104
105 println!(" Count: {}, Total: ${:.2}, Avg: ${:.2} ✅", count, total_value, avg_price);
106 }
107
108 // Example from README - Grouping
109 println!("\nTest 6: Grouping Example");
110 {
111 let products = vec![
112 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
113 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
114 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
115 ];
116
117 let by_category = Query::new(&products).group_by(Product::category_r());
118 println!(" Grouped into {} categories ✅", by_category.len());
119 }
120
121 // Example from README - Pagination
122 println!("\nTest 7: Pagination Example");
123 {
124 let products = vec![
125 Product { id: 1, name: "P1".to_string(), price: 10.0, category: "A".to_string(), stock: 1, rating: 4.0 },
126 Product { id: 2, name: "P2".to_string(), price: 20.0, category: "A".to_string(), stock: 1, rating: 4.0 },
127 Product { id: 3, name: "P3".to_string(), price: 30.0, category: "A".to_string(), stock: 1, rating: 4.0 },
128 ];
129
130 let query = Query::new(&products);
131 let first_10 = query.limit(10);
132 let page_1 = query.skip(0).limit(10);
133
134 println!(" Limited to {} products ✅", first_10.len());
135 println!(" Page 1 has {} products ✅", page_1.len());
136 }
137
138 // Example from README - Join
139 println!("\nTest 8: Join Example");
140 {
141 let users = vec![
142 User { id: 1, name: "Alice".to_string() },
143 User { id: 2, name: "Bob".to_string() },
144 ];
145
146 let orders = vec![
147 Order { id: 101, user_id: 1, total: 99.99 },
148 Order { id: 102, user_id: 1, total: 149.99 },
149 ];
150
151 let user_orders = JoinQuery::new(&users, &orders).inner_join(
152 User::id_r(),
153 Order::user_id_r(),
154 |user, order| (user.name.clone(), order.total),
155 );
156
157 println!(" Joined {} user-order pairs ✅", user_orders.len());
158 }
159
160 // Example from SQL_COMPARISON - SELECT with WHERE
161 println!("\nTest 9: SQL Comparison - SELECT with WHERE");
162 {
163 #[derive(Clone, Keypaths)]
164 struct Employee {
165 department: String,
166 }
167
168 let employees = vec![
169 Employee { department: "Engineering".to_string() },
170 Employee { department: "Sales".to_string() },
171 ];
172
173 let engineering_query = Query::new(&employees)
174 .where_(Employee::department_r(), |dept| dept == "Engineering");
175 let engineering = engineering_query.all();
176
177 println!(" Found {} engineering employees ✅", engineering.len());
178 }
179
180 // Example from USAGE.md - Complex Filtering
181 println!("\nTest 10: USAGE - Complex Filtering");
182 {
183 let products = vec![
184 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
185 ];
186
187 let results_query = Query::new(&products)
188 .where_(Product::category_r(), |cat| cat == "Electronics")
189 .where_(Product::price_r(), |&price| price >= 100.0 && price <= 500.0)
190 .where_(Product::stock_r(), |&stock| stock > 10);
191 let results = results_query.order_by_float(Product::price_r());
192
193 println!(" Filtered {} products ✅", results.len());
194 }
195
196 println!("\n✅ All documentation examples compile and run successfully!");
197}110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}Sourcepub fn skip<'b>(&'b self, offset: usize) -> QueryWithSkip<'a, 'b, T>
pub fn skip<'b>(&'b self, offset: usize) -> QueryWithSkip<'a, 'b, T>
Skips the first offset items for pagination.
§Arguments
offset- The number of items to skip
§Example
let page_2 = query.skip(20).limit(10);Examples found in repository?
28fn main() {
29 println!("╔════════════════════════════════════════════════════════════╗");
30 println!("║ Query Builder Without Clone - Performance Optimization ║");
31 println!("╚════════════════════════════════════════════════════════════╝\n");
32
33 let employees = vec![
34 Employee {
35 id: 1,
36 name: "Alice".to_string(),
37 email: "alice@example.com".to_string(),
38 department: "Engineering".to_string(),
39 salary: 95000.0,
40 large_data: vec![0; 1000], // Large data - expensive to clone!
41 },
42 Employee {
43 id: 2,
44 name: "Bob".to_string(),
45 email: "bob@example.com".to_string(),
46 department: "Engineering".to_string(),
47 salary: 87000.0,
48 large_data: vec![0; 1000],
49 },
50 Employee {
51 id: 3,
52 name: "Carol".to_string(),
53 email: "carol@example.com".to_string(),
54 department: "Sales".to_string(),
55 salary: 75000.0,
56 large_data: vec![0; 1000],
57 },
58 ];
59
60 let departments = vec![
61 Department {
62 id: 1,
63 name: "Engineering".to_string(),
64 budget: 1000000.0,
65 },
66 Department {
67 id: 2,
68 name: "Sales".to_string(),
69 budget: 500000.0,
70 },
71 ];
72
73 println!("✅ Operations that DON'T require Clone:\n");
74
75 // 1. WHERE filtering - returns Vec<&T>
76 println!("1. WHERE filtering (returns references)");
77 let query = Query::new(&employees)
78 .where_(Employee::department_r(), |dept| dept == "Engineering");
79 let engineering = query.all();
80 println!(" Found {} engineering employees", engineering.len());
81 for emp in &engineering {
82 println!(" - {}: ${:.0}", emp.name, emp.salary);
83 }
84
85 // 2. COUNT - no cloning needed
86 println!("\n2. COUNT aggregation");
87 let count = Query::new(&employees)
88 .where_(Employee::salary_r(), |&sal| sal > 80000.0)
89 .count();
90 println!(" {} employees earn over $80k", count);
91
92 // 3. SELECT - only clones the selected field
93 println!("\n3. SELECT (only selected fields are cloned)");
94 let names: Vec<String> = Query::new(&employees)
95 .select(Employee::name_r());
96 println!(" Employee names: {:?}", names);
97
98 // 4. FIRST - returns Option<&T>
99 println!("\n4. FIRST (returns reference)");
100 let query = Query::new(&employees)
101 .where_(Employee::salary_r(), |&sal| sal > 90000.0);
102 if let Some(emp) = query.first() {
103 println!(" First high earner: {} (${:.0})", emp.name, emp.salary);
104 }
105
106 // 5. SUM/AVG aggregations - no cloning
107 println!("\n5. Aggregations (SUM/AVG)");
108 let eng_query = Query::new(&employees)
109 .where_(Employee::department_r(), |dept| dept == "Engineering");
110 let total = eng_query.sum(Employee::salary_r());
111 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
112 println!(" Engineering total: ${:.0}", total);
113 println!(" Engineering average: ${:.0}", avg);
114
115 // 6. MIN/MAX - no cloning
116 println!("\n6. MIN/MAX");
117 let min = Query::new(&employees).min_float(Employee::salary_r());
118 let max = Query::new(&employees).max_float(Employee::salary_r());
119 println!(" Salary range: ${:.0} - ${:.0}", min.unwrap(), max.unwrap());
120
121 // 7. LIMIT - returns Vec<&T>
122 println!("\n7. LIMIT (returns references)");
123 let query = Query::new(&employees);
124 let first_two = query.limit(2);
125 println!(" First 2 employees:");
126 for emp in &first_two {
127 println!(" - {}", emp.name);
128 }
129
130 // 8. SKIP/Pagination - returns Vec<&T>
131 println!("\n8. SKIP/Pagination (returns references)");
132 let query = Query::new(&employees);
133 let page_2 = query.skip(2).limit(1);
134 println!(" Page 2:");
135 for emp in &page_2 {
136 println!(" - {}", emp.name);
137 }
138
139 // 9. EXISTS - just checks
140 println!("\n9. EXISTS check");
141 let has_sales = Query::new(&employees)
142 .where_(Employee::department_r(), |dept| dept == "Sales")
143 .exists();
144 println!(" Has Sales employees: {}", has_sales);
145
146 // 10. JOIN - no Clone required on L or R!
147 println!("\n10. JOIN operations (no Clone required!)");
148 let results = JoinQuery::new(&employees, &departments)
149 .inner_join(
150 Employee::department_r(),
151 Department::name_r(),
152 |emp, dept| {
153 // Mapper only clones what it needs for the result
154 (emp.name.clone(), dept.budget)
155 },
156 );
157 println!(" Employee-Department pairs:");
158 for (name, budget) in &results {
159 println!(" - {} works in dept with ${:.0} budget", name, budget);
160 }
161
162 println!("\n╔════════════════════════════════════════════════════════════╗");
163 println!("║ Operations that REQUIRE Clone (only when needed) ║");
164 println!("╚════════════════════════════════════════════════════════════╝\n");
165
166 println!("⚠️ The following operations require Clone because they return owned Vec<T>:");
167 println!(" - order_by() / order_by_desc()");
168 println!(" - order_by_float() / order_by_float_desc()");
169 println!(" - group_by()");
170 println!("\n To use these, add #[derive(Clone)] to your struct:");
171 println!(" ```rust");
172 println!(" #[derive(Clone, Keypaths)] // Add Clone here");
173 println!(" struct Employee {{ ... }}");
174 println!(" ```");
175
176 println!("\n╔════════════════════════════════════════════════════════════╗");
177 println!("║ Performance Benefits ║");
178 println!("╚════════════════════════════════════════════════════════════╝\n");
179
180 println!("✅ Zero cloning for most operations");
181 println!("✅ Work with large structs efficiently");
182 println!("✅ No unnecessary memory allocations");
183 println!("✅ Only clone when you actually need owned data");
184 println!("✅ Pay for what you use");
185
186 println!("\n✓ Example complete! Most operations work without Clone.\n");
187}More examples
30fn main() {
31 println!("Testing documentation examples...\n");
32
33 // Example from README - Quick Start
34 println!("Test 1: README Quick Start Example");
35 {
36 let products = vec![
37 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
38 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
39 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
40 ];
41
42 let affordable_query = Query::new(&products)
43 .where_(Product::category_r(), |cat| cat == "Electronics")
44 .where_(Product::price_r(), |&price| price < 100.0);
45 let affordable_electronics = affordable_query.all();
46
47 println!(" Found {} affordable electronics ✅", affordable_electronics.len());
48 }
49
50 // Example from README - Filtering
51 println!("\nTest 2: Filtering Example");
52 {
53 let products = vec![
54 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
55 ];
56
57 let electronics_query = Query::new(&products)
58 .where_(Product::category_r(), |cat| cat == "Electronics");
59 let electronics = electronics_query.all();
60
61 println!(" Found {} electronics ✅", electronics.len());
62 }
63
64 // Example from README - Selecting
65 println!("\nTest 3: Selecting Fields Example");
66 {
67 let products = vec![
68 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
69 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
70 ];
71
72 let names: Vec<String> = Query::new(&products)
73 .select(Product::name_r());
74
75 println!(" Selected {} names ✅", names.len());
76 }
77
78 // Example from README - Ordering
79 println!("\nTest 4: Ordering Example");
80 {
81 let products = vec![
82 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
83 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
84 ];
85
86 let by_price = Query::new(&products).order_by_float(Product::price_r());
87 println!(" Ordered {} products ✅", by_price.len());
88 }
89
90 // Example from README - Aggregations
91 println!("\nTest 5: Aggregations Example");
92 {
93 let products = vec![
94 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
95 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
96 ];
97
98 let electronics_query = Query::new(&products)
99 .where_(Product::category_r(), |cat| cat == "Electronics");
100
101 let count = electronics_query.count();
102 let total_value: f64 = electronics_query.sum(Product::price_r());
103 let avg_price = electronics_query.avg(Product::price_r()).unwrap_or(0.0);
104
105 println!(" Count: {}, Total: ${:.2}, Avg: ${:.2} ✅", count, total_value, avg_price);
106 }
107
108 // Example from README - Grouping
109 println!("\nTest 6: Grouping Example");
110 {
111 let products = vec![
112 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
113 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
114 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
115 ];
116
117 let by_category = Query::new(&products).group_by(Product::category_r());
118 println!(" Grouped into {} categories ✅", by_category.len());
119 }
120
121 // Example from README - Pagination
122 println!("\nTest 7: Pagination Example");
123 {
124 let products = vec![
125 Product { id: 1, name: "P1".to_string(), price: 10.0, category: "A".to_string(), stock: 1, rating: 4.0 },
126 Product { id: 2, name: "P2".to_string(), price: 20.0, category: "A".to_string(), stock: 1, rating: 4.0 },
127 Product { id: 3, name: "P3".to_string(), price: 30.0, category: "A".to_string(), stock: 1, rating: 4.0 },
128 ];
129
130 let query = Query::new(&products);
131 let first_10 = query.limit(10);
132 let page_1 = query.skip(0).limit(10);
133
134 println!(" Limited to {} products ✅", first_10.len());
135 println!(" Page 1 has {} products ✅", page_1.len());
136 }
137
138 // Example from README - Join
139 println!("\nTest 8: Join Example");
140 {
141 let users = vec![
142 User { id: 1, name: "Alice".to_string() },
143 User { id: 2, name: "Bob".to_string() },
144 ];
145
146 let orders = vec![
147 Order { id: 101, user_id: 1, total: 99.99 },
148 Order { id: 102, user_id: 1, total: 149.99 },
149 ];
150
151 let user_orders = JoinQuery::new(&users, &orders).inner_join(
152 User::id_r(),
153 Order::user_id_r(),
154 |user, order| (user.name.clone(), order.total),
155 );
156
157 println!(" Joined {} user-order pairs ✅", user_orders.len());
158 }
159
160 // Example from SQL_COMPARISON - SELECT with WHERE
161 println!("\nTest 9: SQL Comparison - SELECT with WHERE");
162 {
163 #[derive(Clone, Keypaths)]
164 struct Employee {
165 department: String,
166 }
167
168 let employees = vec![
169 Employee { department: "Engineering".to_string() },
170 Employee { department: "Sales".to_string() },
171 ];
172
173 let engineering_query = Query::new(&employees)
174 .where_(Employee::department_r(), |dept| dept == "Engineering");
175 let engineering = engineering_query.all();
176
177 println!(" Found {} engineering employees ✅", engineering.len());
178 }
179
180 // Example from USAGE.md - Complex Filtering
181 println!("\nTest 10: USAGE - Complex Filtering");
182 {
183 let products = vec![
184 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
185 ];
186
187 let results_query = Query::new(&products)
188 .where_(Product::category_r(), |cat| cat == "Electronics")
189 .where_(Product::price_r(), |&price| price >= 100.0 && price <= 500.0)
190 .where_(Product::stock_r(), |&stock| stock > 10);
191 let results = results_query.order_by_float(Product::price_r());
192
193 println!(" Filtered {} products ✅", results.len());
194 }
195
196 println!("\n✅ All documentation examples compile and run successfully!");
197}110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}Sourcepub fn select<F>(&self, path: KeyPaths<T, F>) -> Vec<F>where
F: Clone + 'static,
pub fn select<F>(&self, path: KeyPaths<T, F>) -> Vec<F>where
F: Clone + 'static,
Projects/selects a single field from results.
§Arguments
path- The key-path to the field to select
§Example
let names = query.select(Product::name_r());Examples found in repository?
28fn main() {
29 println!("╔════════════════════════════════════════════════════════════╗");
30 println!("║ Query Builder Without Clone - Performance Optimization ║");
31 println!("╚════════════════════════════════════════════════════════════╝\n");
32
33 let employees = vec![
34 Employee {
35 id: 1,
36 name: "Alice".to_string(),
37 email: "alice@example.com".to_string(),
38 department: "Engineering".to_string(),
39 salary: 95000.0,
40 large_data: vec![0; 1000], // Large data - expensive to clone!
41 },
42 Employee {
43 id: 2,
44 name: "Bob".to_string(),
45 email: "bob@example.com".to_string(),
46 department: "Engineering".to_string(),
47 salary: 87000.0,
48 large_data: vec![0; 1000],
49 },
50 Employee {
51 id: 3,
52 name: "Carol".to_string(),
53 email: "carol@example.com".to_string(),
54 department: "Sales".to_string(),
55 salary: 75000.0,
56 large_data: vec![0; 1000],
57 },
58 ];
59
60 let departments = vec![
61 Department {
62 id: 1,
63 name: "Engineering".to_string(),
64 budget: 1000000.0,
65 },
66 Department {
67 id: 2,
68 name: "Sales".to_string(),
69 budget: 500000.0,
70 },
71 ];
72
73 println!("✅ Operations that DON'T require Clone:\n");
74
75 // 1. WHERE filtering - returns Vec<&T>
76 println!("1. WHERE filtering (returns references)");
77 let query = Query::new(&employees)
78 .where_(Employee::department_r(), |dept| dept == "Engineering");
79 let engineering = query.all();
80 println!(" Found {} engineering employees", engineering.len());
81 for emp in &engineering {
82 println!(" - {}: ${:.0}", emp.name, emp.salary);
83 }
84
85 // 2. COUNT - no cloning needed
86 println!("\n2. COUNT aggregation");
87 let count = Query::new(&employees)
88 .where_(Employee::salary_r(), |&sal| sal > 80000.0)
89 .count();
90 println!(" {} employees earn over $80k", count);
91
92 // 3. SELECT - only clones the selected field
93 println!("\n3. SELECT (only selected fields are cloned)");
94 let names: Vec<String> = Query::new(&employees)
95 .select(Employee::name_r());
96 println!(" Employee names: {:?}", names);
97
98 // 4. FIRST - returns Option<&T>
99 println!("\n4. FIRST (returns reference)");
100 let query = Query::new(&employees)
101 .where_(Employee::salary_r(), |&sal| sal > 90000.0);
102 if let Some(emp) = query.first() {
103 println!(" First high earner: {} (${:.0})", emp.name, emp.salary);
104 }
105
106 // 5. SUM/AVG aggregations - no cloning
107 println!("\n5. Aggregations (SUM/AVG)");
108 let eng_query = Query::new(&employees)
109 .where_(Employee::department_r(), |dept| dept == "Engineering");
110 let total = eng_query.sum(Employee::salary_r());
111 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
112 println!(" Engineering total: ${:.0}", total);
113 println!(" Engineering average: ${:.0}", avg);
114
115 // 6. MIN/MAX - no cloning
116 println!("\n6. MIN/MAX");
117 let min = Query::new(&employees).min_float(Employee::salary_r());
118 let max = Query::new(&employees).max_float(Employee::salary_r());
119 println!(" Salary range: ${:.0} - ${:.0}", min.unwrap(), max.unwrap());
120
121 // 7. LIMIT - returns Vec<&T>
122 println!("\n7. LIMIT (returns references)");
123 let query = Query::new(&employees);
124 let first_two = query.limit(2);
125 println!(" First 2 employees:");
126 for emp in &first_two {
127 println!(" - {}", emp.name);
128 }
129
130 // 8. SKIP/Pagination - returns Vec<&T>
131 println!("\n8. SKIP/Pagination (returns references)");
132 let query = Query::new(&employees);
133 let page_2 = query.skip(2).limit(1);
134 println!(" Page 2:");
135 for emp in &page_2 {
136 println!(" - {}", emp.name);
137 }
138
139 // 9. EXISTS - just checks
140 println!("\n9. EXISTS check");
141 let has_sales = Query::new(&employees)
142 .where_(Employee::department_r(), |dept| dept == "Sales")
143 .exists();
144 println!(" Has Sales employees: {}", has_sales);
145
146 // 10. JOIN - no Clone required on L or R!
147 println!("\n10. JOIN operations (no Clone required!)");
148 let results = JoinQuery::new(&employees, &departments)
149 .inner_join(
150 Employee::department_r(),
151 Department::name_r(),
152 |emp, dept| {
153 // Mapper only clones what it needs for the result
154 (emp.name.clone(), dept.budget)
155 },
156 );
157 println!(" Employee-Department pairs:");
158 for (name, budget) in &results {
159 println!(" - {} works in dept with ${:.0} budget", name, budget);
160 }
161
162 println!("\n╔════════════════════════════════════════════════════════════╗");
163 println!("║ Operations that REQUIRE Clone (only when needed) ║");
164 println!("╚════════════════════════════════════════════════════════════╝\n");
165
166 println!("⚠️ The following operations require Clone because they return owned Vec<T>:");
167 println!(" - order_by() / order_by_desc()");
168 println!(" - order_by_float() / order_by_float_desc()");
169 println!(" - group_by()");
170 println!("\n To use these, add #[derive(Clone)] to your struct:");
171 println!(" ```rust");
172 println!(" #[derive(Clone, Keypaths)] // Add Clone here");
173 println!(" struct Employee {{ ... }}");
174 println!(" ```");
175
176 println!("\n╔════════════════════════════════════════════════════════════╗");
177 println!("║ Performance Benefits ║");
178 println!("╚════════════════════════════════════════════════════════════╝\n");
179
180 println!("✅ Zero cloning for most operations");
181 println!("✅ Work with large structs efficiently");
182 println!("✅ No unnecessary memory allocations");
183 println!("✅ Only clone when you actually need owned data");
184 println!("✅ Pay for what you use");
185
186 println!("\n✓ Example complete! Most operations work without Clone.\n");
187}More examples
30fn main() {
31 println!("Testing documentation examples...\n");
32
33 // Example from README - Quick Start
34 println!("Test 1: README Quick Start Example");
35 {
36 let products = vec![
37 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
38 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
39 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
40 ];
41
42 let affordable_query = Query::new(&products)
43 .where_(Product::category_r(), |cat| cat == "Electronics")
44 .where_(Product::price_r(), |&price| price < 100.0);
45 let affordable_electronics = affordable_query.all();
46
47 println!(" Found {} affordable electronics ✅", affordable_electronics.len());
48 }
49
50 // Example from README - Filtering
51 println!("\nTest 2: Filtering Example");
52 {
53 let products = vec![
54 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
55 ];
56
57 let electronics_query = Query::new(&products)
58 .where_(Product::category_r(), |cat| cat == "Electronics");
59 let electronics = electronics_query.all();
60
61 println!(" Found {} electronics ✅", electronics.len());
62 }
63
64 // Example from README - Selecting
65 println!("\nTest 3: Selecting Fields Example");
66 {
67 let products = vec![
68 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
69 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
70 ];
71
72 let names: Vec<String> = Query::new(&products)
73 .select(Product::name_r());
74
75 println!(" Selected {} names ✅", names.len());
76 }
77
78 // Example from README - Ordering
79 println!("\nTest 4: Ordering Example");
80 {
81 let products = vec![
82 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
83 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
84 ];
85
86 let by_price = Query::new(&products).order_by_float(Product::price_r());
87 println!(" Ordered {} products ✅", by_price.len());
88 }
89
90 // Example from README - Aggregations
91 println!("\nTest 5: Aggregations Example");
92 {
93 let products = vec![
94 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
95 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
96 ];
97
98 let electronics_query = Query::new(&products)
99 .where_(Product::category_r(), |cat| cat == "Electronics");
100
101 let count = electronics_query.count();
102 let total_value: f64 = electronics_query.sum(Product::price_r());
103 let avg_price = electronics_query.avg(Product::price_r()).unwrap_or(0.0);
104
105 println!(" Count: {}, Total: ${:.2}, Avg: ${:.2} ✅", count, total_value, avg_price);
106 }
107
108 // Example from README - Grouping
109 println!("\nTest 6: Grouping Example");
110 {
111 let products = vec![
112 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
113 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
114 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
115 ];
116
117 let by_category = Query::new(&products).group_by(Product::category_r());
118 println!(" Grouped into {} categories ✅", by_category.len());
119 }
120
121 // Example from README - Pagination
122 println!("\nTest 7: Pagination Example");
123 {
124 let products = vec![
125 Product { id: 1, name: "P1".to_string(), price: 10.0, category: "A".to_string(), stock: 1, rating: 4.0 },
126 Product { id: 2, name: "P2".to_string(), price: 20.0, category: "A".to_string(), stock: 1, rating: 4.0 },
127 Product { id: 3, name: "P3".to_string(), price: 30.0, category: "A".to_string(), stock: 1, rating: 4.0 },
128 ];
129
130 let query = Query::new(&products);
131 let first_10 = query.limit(10);
132 let page_1 = query.skip(0).limit(10);
133
134 println!(" Limited to {} products ✅", first_10.len());
135 println!(" Page 1 has {} products ✅", page_1.len());
136 }
137
138 // Example from README - Join
139 println!("\nTest 8: Join Example");
140 {
141 let users = vec![
142 User { id: 1, name: "Alice".to_string() },
143 User { id: 2, name: "Bob".to_string() },
144 ];
145
146 let orders = vec![
147 Order { id: 101, user_id: 1, total: 99.99 },
148 Order { id: 102, user_id: 1, total: 149.99 },
149 ];
150
151 let user_orders = JoinQuery::new(&users, &orders).inner_join(
152 User::id_r(),
153 Order::user_id_r(),
154 |user, order| (user.name.clone(), order.total),
155 );
156
157 println!(" Joined {} user-order pairs ✅", user_orders.len());
158 }
159
160 // Example from SQL_COMPARISON - SELECT with WHERE
161 println!("\nTest 9: SQL Comparison - SELECT with WHERE");
162 {
163 #[derive(Clone, Keypaths)]
164 struct Employee {
165 department: String,
166 }
167
168 let employees = vec![
169 Employee { department: "Engineering".to_string() },
170 Employee { department: "Sales".to_string() },
171 ];
172
173 let engineering_query = Query::new(&employees)
174 .where_(Employee::department_r(), |dept| dept == "Engineering");
175 let engineering = engineering_query.all();
176
177 println!(" Found {} engineering employees ✅", engineering.len());
178 }
179
180 // Example from USAGE.md - Complex Filtering
181 println!("\nTest 10: USAGE - Complex Filtering");
182 {
183 let products = vec![
184 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
185 ];
186
187 let results_query = Query::new(&products)
188 .where_(Product::category_r(), |cat| cat == "Electronics")
189 .where_(Product::price_r(), |&price| price >= 100.0 && price <= 500.0)
190 .where_(Product::stock_r(), |&stock| stock > 10);
191 let results = results_query.order_by_float(Product::price_r());
192
193 println!(" Filtered {} products ✅", results.len());
194 }
195
196 println!("\n✅ All documentation examples compile and run successfully!");
197}110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}84fn main() {
85 let employees = create_employees();
86 let departments = create_departments();
87 let projects = create_projects();
88
89 println!("\n╔════════════════════════════════════════════════════════════════════════╗");
90 println!("║ SQL vs Rust Query Builder Comparison ║");
91 println!("║ Demonstrating equivalent operations ║");
92 println!("╚════════════════════════════════════════════════════════════════════════╝");
93
94 // ============================================================================
95 // EXAMPLE 1: Simple SELECT with WHERE
96 // ============================================================================
97 print_separator("Example 1: SELECT with WHERE clause");
98 print_query(
99 "SELECT * FROM employees WHERE department = 'Engineering';",
100 "Filter employees by department"
101 );
102
103 let eng_query = Query::new(&employees)
104 .where_(Employee::department_r(), |dept| dept == "Engineering");
105 let engineering_employees = eng_query.all();
106
107 for emp in &engineering_employees {
108 println!(" ID: {}, Name: {}, Salary: ${:.2}", emp.id, emp.name, emp.salary);
109 }
110 println!("\nRust Query Builder:");
111 println!("Query::new(&employees)");
112 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\")");
113 println!(" .all()");
114 println!("✓ Found {} employees", engineering_employees.len());
115
116 // ============================================================================
117 // EXAMPLE 2: SELECT specific columns
118 // ============================================================================
119 print_separator("Example 2: SELECT specific columns (Projection)");
120 print_query(
121 "SELECT name FROM employees WHERE salary > 80000;",
122 "Get names of high-earning employees"
123 );
124
125 let high_earners = Query::new(&employees)
126 .where_(Employee::salary_r(), |&salary| salary > 80000.0)
127 .select(Employee::name_r());
128
129 for name in &high_earners {
130 println!(" {}", name);
131 }
132 println!("\nRust Query Builder:");
133 println!("Query::new(&employees)");
134 println!(" .where_(Employee::salary_r(), |&salary| salary > 80000.0)");
135 println!(" .select(Employee::name_r())");
136 println!("✓ Found {} employees", high_earners.len());
137
138 // ============================================================================
139 // EXAMPLE 3: COUNT
140 // ============================================================================
141 print_separator("Example 3: COUNT aggregation");
142 print_query(
143 "SELECT COUNT(*) FROM employees WHERE age < 30;",
144 "Count young employees"
145 );
146
147 let young_count = Query::new(&employees)
148 .where_(Employee::age_r(), |&age| age < 30)
149 .count();
150
151 println!(" Count: {}", young_count);
152 println!("\nRust Query Builder:");
153 println!("Query::new(&employees)");
154 println!(" .where_(Employee::age_r(), |&age| age < 30)");
155 println!(" .count()");
156 println!("✓ Result: {}", young_count);
157
158 // ============================================================================
159 // EXAMPLE 4: SUM, AVG, MIN, MAX
160 // ============================================================================
161 print_separator("Example 4: Aggregate functions (SUM, AVG, MIN, MAX)");
162 print_query(
163 "SELECT \n\
164 SUM(salary) as total_salary,\n\
165 AVG(salary) as avg_salary,\n\
166 MIN(salary) as min_salary,\n\
167 MAX(salary) as max_salary\n\
168 FROM employees WHERE department = 'Engineering';",
169 "Engineering department salary statistics"
170 );
171
172 let eng_query = Query::new(&employees)
173 .where_(Employee::department_r(), |dept| dept == "Engineering");
174
175 let total = eng_query.sum(Employee::salary_r());
176 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
177 let min = eng_query.min_float(Employee::salary_r()).unwrap_or(0.0);
178 let max = eng_query.max_float(Employee::salary_r()).unwrap_or(0.0);
179
180 println!(" Total Salary: ${:.2}", total);
181 println!(" Avg Salary: ${:.2}", avg);
182 println!(" Min Salary: ${:.2}", min);
183 println!(" Max Salary: ${:.2}", max);
184
185 println!("\nRust Query Builder:");
186 println!("let query = Query::new(&employees)");
187 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\");");
188 println!("query.sum(Employee::salary_r()) // ${:.2}", total);
189 println!("query.avg(Employee::salary_r()) // ${:.2}", avg);
190 println!("query.min_float(Employee::salary_r()) // ${:.2}", min);
191 println!("query.max_float(Employee::salary_r()) // ${:.2}", max);
192
193 // ============================================================================
194 // EXAMPLE 5: GROUP BY with aggregation
195 // ============================================================================
196 print_separator("Example 5: GROUP BY with aggregation");
197 print_query(
198 "SELECT \n\
199 department,\n\
200 COUNT(*) as emp_count,\n\
201 AVG(salary) as avg_salary\n\
202 FROM employees\n\
203 GROUP BY department;",
204 "Statistics by department"
205 );
206
207 let by_dept = Query::new(&employees).group_by(Employee::department_r());
208
209 for (dept, emps) in &by_dept {
210 let dept_query = Query::new(emps);
211 let count = emps.len();
212 let avg_sal = dept_query.avg(Employee::salary_r()).unwrap_or(0.0);
213 println!(" {}: {} employees, avg salary ${:.2}", dept, count, avg_sal);
214 }
215
216 println!("\nRust Query Builder:");
217 println!("let by_dept = Query::new(&employees).group_by(Employee::department_r());");
218 println!("for (dept, emps) in &by_dept {{");
219 println!(" let dept_query = Query::new(emps);");
220 println!(" dept_query.avg(Employee::salary_r())");
221 println!("}}");
222
223 // ============================================================================
224 // EXAMPLE 6: ORDER BY
225 // ============================================================================
226 print_separator("Example 6: ORDER BY");
227 print_query(
228 "SELECT name, salary FROM employees\n\
229 WHERE department = 'Sales'\n\
230 ORDER BY salary DESC;",
231 "Sales employees ordered by salary (descending)"
232 );
233
234 let sales_sorted = Query::new(&employees)
235 .where_(Employee::department_r(), |dept| dept == "Sales")
236 .order_by_float_desc(Employee::salary_r());
237
238 for emp in &sales_sorted {
239 println!(" {}: ${:.2}", emp.name, emp.salary);
240 }
241
242 println!("\nRust Query Builder:");
243 println!("Query::new(&employees)");
244 println!(" .where_(Employee::department_r(), |dept| dept == \"Sales\")");
245 println!(" .order_by_float_desc(Employee::salary_r())");
246
247 // ============================================================================
248 // EXAMPLE 7: Multiple WHERE conditions (AND)
249 // ============================================================================
250 print_separator("Example 7: Multiple WHERE conditions (AND)");
251 print_query(
252 "SELECT * FROM employees\n\
253 WHERE salary > 70000 AND age < 35;",
254 "High-earning young employees"
255 );
256
257 let filter_query = Query::new(&employees)
258 .where_(Employee::salary_r(), |&salary| salary > 70000.0)
259 .where_(Employee::age_r(), |&age| age < 35);
260 let filtered = filter_query.all();
261
262 for emp in &filtered {
263 println!(" {}: Age {}, Salary ${:.2}", emp.name, emp.age, emp.salary);
264 }
265
266 println!("\nRust Query Builder:");
267 println!("Query::new(&employees)");
268 println!(" .where_(Employee::salary_r(), |&salary| salary > 70000.0)");
269 println!(" .where_(Employee::age_r(), |&age| age < 35)");
270 println!(" .all()");
271 println!("✓ Found {} employees", filtered.len());
272
273 // ============================================================================
274 // EXAMPLE 8: LIMIT (TOP N)
275 // ============================================================================
276 print_separator("Example 8: LIMIT / TOP N");
277 print_query(
278 "SELECT TOP 3 name, salary FROM employees\n\
279 ORDER BY salary DESC;",
280 "Top 3 highest paid employees"
281 );
282
283 let top_earners = Query::new(&employees)
284 .order_by_float_desc(Employee::salary_r());
285
286 for (i, emp) in top_earners.iter().take(3).enumerate() {
287 println!(" {}. {}: ${:.2}", i + 1, emp.name, emp.salary);
288 }
289
290 println!("\nRust Query Builder:");
291 println!("Query::new(&employees)");
292 println!(" .order_by_float_desc(Employee::salary_r())");
293 println!(" .into_iter().take(3)");
294
295 // ============================================================================
296 // EXAMPLE 9: OFFSET and LIMIT (Pagination)
297 // ============================================================================
298 print_separator("Example 9: OFFSET and LIMIT (Pagination)");
299 print_query(
300 "SELECT name FROM employees\n\
301 ORDER BY name\n\
302 LIMIT 3 OFFSET 3;",
303 "Page 2 of employee names (3 per page)"
304 );
305
306 let page_2 = Query::new(&employees)
307 .order_by(Employee::name_r())
308 .into_iter()
309 .skip(3)
310 .take(3)
311 .collect::<Vec<_>>();
312
313 for emp in &page_2 {
314 println!(" {}", emp.name);
315 }
316
317 println!("\nRust Query Builder:");
318 println!("Query::new(&employees)");
319 println!(" .order_by(Employee::name_r())");
320 println!(" .into_iter().skip(3).take(3)");
321
322 // ============================================================================
323 // EXAMPLE 10: INNER JOIN
324 // ============================================================================
325 print_separator("Example 10: INNER JOIN");
326 print_query(
327 "SELECT e.name, d.name as dept_name, d.budget\n\
328 FROM employees e\n\
329 INNER JOIN departments d ON e.department = d.name;",
330 "Employees with their department info"
331 );
332
333 let emp_dept = JoinQuery::new(&employees, &departments).inner_join(
334 Employee::department_r(),
335 Department::name_r(),
336 |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget),
337 );
338
339 for (emp_name, dept_name, budget) in emp_dept.iter().take(5) {
340 println!(" {} works in {} (Budget: ${:.0})", emp_name, dept_name, budget);
341 }
342 println!(" ... (showing first 5)");
343
344 println!("\nRust Query Builder:");
345 println!("JoinQuery::new(&employees, &departments).inner_join(");
346 println!(" Employee::department_r(),");
347 println!(" Department::name_r(),");
348 println!(" |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget)");
349 println!(")");
350 println!("✓ Found {} matches", emp_dept.len());
351
352 // ============================================================================
353 // EXAMPLE 11: GROUP BY with HAVING equivalent
354 // ============================================================================
355 print_separator("Example 11: GROUP BY with filtering (HAVING equivalent)");
356 print_query(
357 "SELECT city, COUNT(*) as emp_count, AVG(salary) as avg_salary\n\
358 FROM employees\n\
359 GROUP BY city\n\
360 HAVING COUNT(*) > 1;",
361 "Cities with multiple employees"
362 );
363
364 let by_city = Query::new(&employees).group_by(Employee::city_r());
365 let mut city_stats: Vec<_> = by_city
366 .iter()
367 .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent
368 .map(|(city, emps)| {
369 let avg_sal = Query::new(emps).avg(Employee::salary_r()).unwrap_or(0.0);
370 (city.clone(), emps.len(), avg_sal)
371 })
372 .collect();
373
374 city_stats.sort_by(|a, b| b.1.cmp(&a.1)); // Sort by count
375
376 for (city, count, avg_sal) in &city_stats {
377 println!(" {}: {} employees, avg salary ${:.2}", city, count, avg_sal);
378 }
379
380 println!("\nRust Query Builder:");
381 println!("let by_city = Query::new(&employees).group_by(Employee::city_r());");
382 println!("by_city.iter()");
383 println!(" .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent");
384 println!(" .map(|(city, emps)| {{");
385 println!(" let avg = Query::new(emps).avg(Employee::salary_r());");
386 println!(" (city, emps.len(), avg)");
387 println!(" }})");
388
389 // ============================================================================
390 // EXAMPLE 12: Complex query with multiple operations
391 // ============================================================================
392 print_separator("Example 12: Complex multi-operation query");
393 print_query(
394 "SELECT name, salary, age\n\
395 FROM employees\n\
396 WHERE department IN ('Engineering', 'Sales')\n\
397 AND salary BETWEEN 80000 AND 100000\n\
398 AND age >= 30\n\
399 ORDER BY salary DESC;",
400 "Experienced mid-to-senior level employees in core departments"
401 );
402
403 let complex_query = Query::new(&employees)
404 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
405 .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)
406 .where_(Employee::age_r(), |&age| age >= 30)
407 .order_by_float_desc(Employee::salary_r());
408
409 for emp in &complex_query {
410 println!(" {}: Age {}, {} dept, ${:.2}", emp.name, emp.age, emp.department, emp.salary);
411 }
412
413 println!("\nRust Query Builder:");
414 println!("Query::new(&employees)");
415 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\" || dept == \"Sales\")");
416 println!(" .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)");
417 println!(" .where_(Employee::age_r(), |&age| age >= 30)");
418 println!(" .order_by_float_desc(Employee::salary_r())");
419 println!("✓ Found {} employees", complex_query.len());
420
421 // ============================================================================
422 // EXAMPLE 13: Three-table JOIN
423 // ============================================================================
424 print_separator("Example 13: Three-table JOIN");
425 print_query(
426 "SELECT p.name as project, d.name as department, d.location\n\
427 FROM projects p\n\
428 INNER JOIN departments d ON p.department_id = d.id;",
429 "Projects with their department details"
430 );
431
432 let proj_dept = JoinQuery::new(&projects, &departments).inner_join(
433 Project::department_id_r(),
434 Department::id_r(),
435 |proj, dept| {
436 (proj.name.clone(), dept.name.clone(), dept.location.clone(), proj.budget)
437 },
438 );
439
440 for (proj_name, dept_name, location, budget) in &proj_dept {
441 println!(" {}: {} dept in {} (${:.0})", proj_name, dept_name, location, budget);
442 }
443
444 println!("\nRust Query Builder:");
445 println!("JoinQuery::new(&projects, &departments).inner_join(");
446 println!(" Project::department_id_r(),");
447 println!(" Department::id_r(),");
448 println!(" |proj, dept| (proj.name, dept.name, dept.location, proj.budget)");
449 println!(")");
450
451 // ============================================================================
452 // EXAMPLE 14: Subquery equivalent (using intermediate results)
453 // ============================================================================
454 print_separator("Example 14: Subquery equivalent");
455 print_query(
456 "SELECT * FROM employees\n\
457 WHERE salary > (SELECT AVG(salary) FROM employees);",
458 "Employees earning above average"
459 );
460
461 let avg_salary = Query::new(&employees)
462 .avg(Employee::salary_r())
463 .unwrap_or(0.0);
464
465 let above_avg_query = Query::new(&employees)
466 .where_(Employee::salary_r(), move |&sal| sal > avg_salary);
467 let above_avg = above_avg_query.all();
468
469 println!(" Average salary: ${:.2}", avg_salary);
470 for emp in &above_avg {
471 println!(" {}: ${:.2} ({:.1}% above average)",
472 emp.name, emp.salary, ((emp.salary - avg_salary) / avg_salary * 100.0));
473 }
474
475 println!("\nRust Query Builder:");
476 println!("let avg = Query::new(&employees).avg(Employee::salary_r()).unwrap_or(0.0);");
477 println!("Query::new(&employees)");
478 println!(" .where_(Employee::salary_r(), |&sal| sal > avg)");
479 println!(" .all()");
480 println!("✓ Found {} employees above average", above_avg.len());
481
482 // ============================================================================
483 // EXAMPLE 15: Advanced aggregation (revenue calculation)
484 // ============================================================================
485 print_separator("Example 15: Advanced aggregation");
486 print_query(
487 "SELECT \n\
488 d.name,\n\
489 d.budget as dept_budget,\n\
490 SUM(p.budget) as total_project_budget,\n\
491 (d.budget - SUM(p.budget)) as remaining_budget\n\
492 FROM departments d\n\
493 LEFT JOIN projects p ON d.id = p.department_id\n\
494 GROUP BY d.name, d.budget;",
495 "Department budget utilization"
496 );
497
498 // Join departments with projects
499 let dept_projects = JoinQuery::new(&departments, &projects).left_join(
500 Department::id_r(),
501 Project::department_id_r(),
502 |dept, proj| (dept.clone(), proj.map(|p| p.clone())),
503 );
504
505 // Aggregate by department
506 let mut dept_budget_map: HashMap<String, (f64, Vec<f64>)> = HashMap::new();
507 for (dept, proj) in dept_projects {
508 let entry = dept_budget_map
509 .entry(dept.name.clone())
510 .or_insert((dept.budget, Vec::new()));
511 if let Some(p) = proj {
512 entry.1.push(p.budget);
513 }
514 }
515
516 for (dept_name, (total_budget, project_budgets)) in dept_budget_map.iter() {
517 let used: f64 = project_budgets.iter().sum();
518 let remaining = total_budget - used;
519 println!(" {}: Budget ${:.0}, Used ${:.0}, Remaining ${:.0} ({:.1}% utilized)",
520 dept_name, total_budget, used, remaining, (used / total_budget * 100.0));
521 }
522
523 println!("\nRust Query Builder:");
524 println!("let dept_projects = JoinQuery::new(&departments, &projects)");
525 println!(" .left_join(Department::id_r(), Project::department_id_r(), ...)");
526 println!("// Then aggregate using HashMap");
527
528 // ============================================================================
529 // Summary
530 // ============================================================================
531 print_separator("Summary");
532 println!("\n✓ All 15 SQL queries successfully replicated with Rust Query Builder!");
533 println!("\nDemonstrated equivalents for:");
534 println!(" • SELECT with WHERE");
535 println!(" • Projection (SELECT specific columns)");
536 println!(" • Aggregations (COUNT, SUM, AVG, MIN, MAX)");
537 println!(" • GROUP BY");
538 println!(" • ORDER BY");
539 println!(" • LIMIT and OFFSET");
540 println!(" • INNER JOIN and LEFT JOIN");
541 println!(" • Complex conditions (AND, OR, BETWEEN)");
542 println!(" • Subqueries");
543 println!(" • Multi-table operations");
544 println!("\n🎯 Type-safe, compile-time checked, and zero runtime overhead!");
545 println!();
546}Sourcepub fn sum<F>(&self, path: KeyPaths<T, F>) -> F
pub fn sum<F>(&self, path: KeyPaths<T, F>) -> F
Computes the sum of a numeric field.
§Arguments
path- The key-path to the numeric field
§Example
let total_price = query.sum(Product::price_r());Examples found in repository?
28fn main() {
29 println!("╔════════════════════════════════════════════════════════════╗");
30 println!("║ Query Builder Without Clone - Performance Optimization ║");
31 println!("╚════════════════════════════════════════════════════════════╝\n");
32
33 let employees = vec![
34 Employee {
35 id: 1,
36 name: "Alice".to_string(),
37 email: "alice@example.com".to_string(),
38 department: "Engineering".to_string(),
39 salary: 95000.0,
40 large_data: vec![0; 1000], // Large data - expensive to clone!
41 },
42 Employee {
43 id: 2,
44 name: "Bob".to_string(),
45 email: "bob@example.com".to_string(),
46 department: "Engineering".to_string(),
47 salary: 87000.0,
48 large_data: vec![0; 1000],
49 },
50 Employee {
51 id: 3,
52 name: "Carol".to_string(),
53 email: "carol@example.com".to_string(),
54 department: "Sales".to_string(),
55 salary: 75000.0,
56 large_data: vec![0; 1000],
57 },
58 ];
59
60 let departments = vec![
61 Department {
62 id: 1,
63 name: "Engineering".to_string(),
64 budget: 1000000.0,
65 },
66 Department {
67 id: 2,
68 name: "Sales".to_string(),
69 budget: 500000.0,
70 },
71 ];
72
73 println!("✅ Operations that DON'T require Clone:\n");
74
75 // 1. WHERE filtering - returns Vec<&T>
76 println!("1. WHERE filtering (returns references)");
77 let query = Query::new(&employees)
78 .where_(Employee::department_r(), |dept| dept == "Engineering");
79 let engineering = query.all();
80 println!(" Found {} engineering employees", engineering.len());
81 for emp in &engineering {
82 println!(" - {}: ${:.0}", emp.name, emp.salary);
83 }
84
85 // 2. COUNT - no cloning needed
86 println!("\n2. COUNT aggregation");
87 let count = Query::new(&employees)
88 .where_(Employee::salary_r(), |&sal| sal > 80000.0)
89 .count();
90 println!(" {} employees earn over $80k", count);
91
92 // 3. SELECT - only clones the selected field
93 println!("\n3. SELECT (only selected fields are cloned)");
94 let names: Vec<String> = Query::new(&employees)
95 .select(Employee::name_r());
96 println!(" Employee names: {:?}", names);
97
98 // 4. FIRST - returns Option<&T>
99 println!("\n4. FIRST (returns reference)");
100 let query = Query::new(&employees)
101 .where_(Employee::salary_r(), |&sal| sal > 90000.0);
102 if let Some(emp) = query.first() {
103 println!(" First high earner: {} (${:.0})", emp.name, emp.salary);
104 }
105
106 // 5. SUM/AVG aggregations - no cloning
107 println!("\n5. Aggregations (SUM/AVG)");
108 let eng_query = Query::new(&employees)
109 .where_(Employee::department_r(), |dept| dept == "Engineering");
110 let total = eng_query.sum(Employee::salary_r());
111 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
112 println!(" Engineering total: ${:.0}", total);
113 println!(" Engineering average: ${:.0}", avg);
114
115 // 6. MIN/MAX - no cloning
116 println!("\n6. MIN/MAX");
117 let min = Query::new(&employees).min_float(Employee::salary_r());
118 let max = Query::new(&employees).max_float(Employee::salary_r());
119 println!(" Salary range: ${:.0} - ${:.0}", min.unwrap(), max.unwrap());
120
121 // 7. LIMIT - returns Vec<&T>
122 println!("\n7. LIMIT (returns references)");
123 let query = Query::new(&employees);
124 let first_two = query.limit(2);
125 println!(" First 2 employees:");
126 for emp in &first_two {
127 println!(" - {}", emp.name);
128 }
129
130 // 8. SKIP/Pagination - returns Vec<&T>
131 println!("\n8. SKIP/Pagination (returns references)");
132 let query = Query::new(&employees);
133 let page_2 = query.skip(2).limit(1);
134 println!(" Page 2:");
135 for emp in &page_2 {
136 println!(" - {}", emp.name);
137 }
138
139 // 9. EXISTS - just checks
140 println!("\n9. EXISTS check");
141 let has_sales = Query::new(&employees)
142 .where_(Employee::department_r(), |dept| dept == "Sales")
143 .exists();
144 println!(" Has Sales employees: {}", has_sales);
145
146 // 10. JOIN - no Clone required on L or R!
147 println!("\n10. JOIN operations (no Clone required!)");
148 let results = JoinQuery::new(&employees, &departments)
149 .inner_join(
150 Employee::department_r(),
151 Department::name_r(),
152 |emp, dept| {
153 // Mapper only clones what it needs for the result
154 (emp.name.clone(), dept.budget)
155 },
156 );
157 println!(" Employee-Department pairs:");
158 for (name, budget) in &results {
159 println!(" - {} works in dept with ${:.0} budget", name, budget);
160 }
161
162 println!("\n╔════════════════════════════════════════════════════════════╗");
163 println!("║ Operations that REQUIRE Clone (only when needed) ║");
164 println!("╚════════════════════════════════════════════════════════════╝\n");
165
166 println!("⚠️ The following operations require Clone because they return owned Vec<T>:");
167 println!(" - order_by() / order_by_desc()");
168 println!(" - order_by_float() / order_by_float_desc()");
169 println!(" - group_by()");
170 println!("\n To use these, add #[derive(Clone)] to your struct:");
171 println!(" ```rust");
172 println!(" #[derive(Clone, Keypaths)] // Add Clone here");
173 println!(" struct Employee {{ ... }}");
174 println!(" ```");
175
176 println!("\n╔════════════════════════════════════════════════════════════╗");
177 println!("║ Performance Benefits ║");
178 println!("╚════════════════════════════════════════════════════════════╝\n");
179
180 println!("✅ Zero cloning for most operations");
181 println!("✅ Work with large structs efficiently");
182 println!("✅ No unnecessary memory allocations");
183 println!("✅ Only clone when you actually need owned data");
184 println!("✅ Pay for what you use");
185
186 println!("\n✓ Example complete! Most operations work without Clone.\n");
187}More examples
30fn main() {
31 println!("Testing documentation examples...\n");
32
33 // Example from README - Quick Start
34 println!("Test 1: README Quick Start Example");
35 {
36 let products = vec![
37 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
38 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
39 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
40 ];
41
42 let affordable_query = Query::new(&products)
43 .where_(Product::category_r(), |cat| cat == "Electronics")
44 .where_(Product::price_r(), |&price| price < 100.0);
45 let affordable_electronics = affordable_query.all();
46
47 println!(" Found {} affordable electronics ✅", affordable_electronics.len());
48 }
49
50 // Example from README - Filtering
51 println!("\nTest 2: Filtering Example");
52 {
53 let products = vec![
54 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
55 ];
56
57 let electronics_query = Query::new(&products)
58 .where_(Product::category_r(), |cat| cat == "Electronics");
59 let electronics = electronics_query.all();
60
61 println!(" Found {} electronics ✅", electronics.len());
62 }
63
64 // Example from README - Selecting
65 println!("\nTest 3: Selecting Fields Example");
66 {
67 let products = vec![
68 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
69 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
70 ];
71
72 let names: Vec<String> = Query::new(&products)
73 .select(Product::name_r());
74
75 println!(" Selected {} names ✅", names.len());
76 }
77
78 // Example from README - Ordering
79 println!("\nTest 4: Ordering Example");
80 {
81 let products = vec![
82 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
83 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
84 ];
85
86 let by_price = Query::new(&products).order_by_float(Product::price_r());
87 println!(" Ordered {} products ✅", by_price.len());
88 }
89
90 // Example from README - Aggregations
91 println!("\nTest 5: Aggregations Example");
92 {
93 let products = vec![
94 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
95 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
96 ];
97
98 let electronics_query = Query::new(&products)
99 .where_(Product::category_r(), |cat| cat == "Electronics");
100
101 let count = electronics_query.count();
102 let total_value: f64 = electronics_query.sum(Product::price_r());
103 let avg_price = electronics_query.avg(Product::price_r()).unwrap_or(0.0);
104
105 println!(" Count: {}, Total: ${:.2}, Avg: ${:.2} ✅", count, total_value, avg_price);
106 }
107
108 // Example from README - Grouping
109 println!("\nTest 6: Grouping Example");
110 {
111 let products = vec![
112 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
113 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
114 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
115 ];
116
117 let by_category = Query::new(&products).group_by(Product::category_r());
118 println!(" Grouped into {} categories ✅", by_category.len());
119 }
120
121 // Example from README - Pagination
122 println!("\nTest 7: Pagination Example");
123 {
124 let products = vec![
125 Product { id: 1, name: "P1".to_string(), price: 10.0, category: "A".to_string(), stock: 1, rating: 4.0 },
126 Product { id: 2, name: "P2".to_string(), price: 20.0, category: "A".to_string(), stock: 1, rating: 4.0 },
127 Product { id: 3, name: "P3".to_string(), price: 30.0, category: "A".to_string(), stock: 1, rating: 4.0 },
128 ];
129
130 let query = Query::new(&products);
131 let first_10 = query.limit(10);
132 let page_1 = query.skip(0).limit(10);
133
134 println!(" Limited to {} products ✅", first_10.len());
135 println!(" Page 1 has {} products ✅", page_1.len());
136 }
137
138 // Example from README - Join
139 println!("\nTest 8: Join Example");
140 {
141 let users = vec![
142 User { id: 1, name: "Alice".to_string() },
143 User { id: 2, name: "Bob".to_string() },
144 ];
145
146 let orders = vec![
147 Order { id: 101, user_id: 1, total: 99.99 },
148 Order { id: 102, user_id: 1, total: 149.99 },
149 ];
150
151 let user_orders = JoinQuery::new(&users, &orders).inner_join(
152 User::id_r(),
153 Order::user_id_r(),
154 |user, order| (user.name.clone(), order.total),
155 );
156
157 println!(" Joined {} user-order pairs ✅", user_orders.len());
158 }
159
160 // Example from SQL_COMPARISON - SELECT with WHERE
161 println!("\nTest 9: SQL Comparison - SELECT with WHERE");
162 {
163 #[derive(Clone, Keypaths)]
164 struct Employee {
165 department: String,
166 }
167
168 let employees = vec![
169 Employee { department: "Engineering".to_string() },
170 Employee { department: "Sales".to_string() },
171 ];
172
173 let engineering_query = Query::new(&employees)
174 .where_(Employee::department_r(), |dept| dept == "Engineering");
175 let engineering = engineering_query.all();
176
177 println!(" Found {} engineering employees ✅", engineering.len());
178 }
179
180 // Example from USAGE.md - Complex Filtering
181 println!("\nTest 10: USAGE - Complex Filtering");
182 {
183 let products = vec![
184 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
185 ];
186
187 let results_query = Query::new(&products)
188 .where_(Product::category_r(), |cat| cat == "Electronics")
189 .where_(Product::price_r(), |&price| price >= 100.0 && price <= 500.0)
190 .where_(Product::stock_r(), |&stock| stock > 10);
191 let results = results_query.order_by_float(Product::price_r());
192
193 println!(" Filtered {} products ✅", results.len());
194 }
195
196 println!("\n✅ All documentation examples compile and run successfully!");
197}110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}26fn main() {
27 println!("\n╔════════════════════════════════════════════════════════════════╗");
28 println!("║ Container Support Demo ║");
29 println!("║ Query various collection types ║");
30 println!("╚════════════════════════════════════════════════════════════════╝\n");
31
32 // ============================================================================
33 // CONTAINER 1: Vec<T>
34 // ============================================================================
35 println!("═══════════════════════════════════════════════════════════════");
36 println!("Container 1: Vec<T>");
37 println!("═══════════════════════════════════════════════════════════════\n");
38
39 let vec_products = vec![
40 create_sample_product(1, "Laptop", 999, "Electronics"),
41 create_sample_product(2, "Mouse", 29, "Electronics"),
42 create_sample_product(3, "Desk", 299, "Furniture"),
43 ];
44
45 // Query Vec directly
46 let vec_query = Query::new(&vec_products)
47 .where_(Product::category_r(), |cat| cat == "Electronics");
48 let vec_results = vec_query.all();
49 println!(" Vec: Found {} electronics", vec_results.len());
50
51 // Lazy query on Vec
52 let lazy_count = LazyQuery::new(&vec_products)
53 .where_(Product::price_r(), |&p| p < 100)
54 .count();
55 println!(" Vec (lazy): {} items under $100", lazy_count);
56
57 // ============================================================================
58 // CONTAINER 2: VecDeque<T>
59 // ============================================================================
60 println!("\n═══════════════════════════════════════════════════════════════");
61 println!("Container 2: VecDeque<T>");
62 println!("═══════════════════════════════════════════════════════════════\n");
63
64 let mut deque_products = VecDeque::new();
65 deque_products.push_back(create_sample_product(1, "Keyboard", 129, "Electronics"));
66 deque_products.push_back(create_sample_product(2, "Monitor", 349, "Electronics"));
67 deque_products.push_back(create_sample_product(3, "Chair", 199, "Furniture"));
68
69 // Convert to owned Vec for querying
70 let deque_vec: Vec<Product> = deque_products.iter().cloned().collect();
71 let deque_query = Query::new(&deque_vec);
72 let deque_count = deque_query.count();
73 println!(" VecDeque: {} total items", deque_count);
74
75 // More efficient: use make_contiguous for zero-copy slice access
76 let contiguous = deque_products.make_contiguous();
77 let contiguous_query = Query::new(contiguous);
78 println!(" VecDeque (zero-copy): {} items", contiguous_query.count());
79
80 // ============================================================================
81 // CONTAINER 3: HashSet<T>
82 // ============================================================================
83 println!("\n═══════════════════════════════════════════════════════════════");
84 println!("Container 3: HashSet<T>");
85 println!("═══════════════════════════════════════════════════════════════\n");
86
87 let mut set_products = HashSet::new();
88 set_products.insert(create_sample_product(1, "Tablet", 499, "Electronics"));
89 set_products.insert(create_sample_product(2, "Phone", 799, "Electronics"));
90 set_products.insert(create_sample_product(3, "Lamp", 39, "Furniture"));
91
92 // Collect from HashSet to Vec for querying
93 let set_vec: Vec<Product> = set_products.iter().cloned().collect();
94 let set_query = Query::new(&set_vec)
95 .where_(Product::price_r(), |&p| p > 500);
96 let expensive = set_query.all();
97 println!(" HashSet: {} expensive items", expensive.len());
98
99 // Lazy on HashSet (convert to owned Vec first)
100 let set_owned: Vec<Product> = set_products.iter().cloned().collect();
101 let lazy_set: Vec<_> = LazyQuery::new(&set_owned)
102 .where_(Product::category_r(), |cat| cat == "Electronics")
103 .collect();
104 println!(" HashSet (lazy): {} electronics", lazy_set.len());
105
106 // ============================================================================
107 // CONTAINER 4: BTreeSet<T>
108 // ============================================================================
109 println!("\n═══════════════════════════════════════════════════════════════");
110 println!("Container 4: BTreeSet<T>");
111 println!("═══════════════════════════════════════════════════════════════\n");
112
113 let mut btree_set = BTreeSet::new();
114 btree_set.insert(create_sample_product(1, "Webcam", 79, "Electronics"));
115 btree_set.insert(create_sample_product(2, "Microphone", 129, "Electronics"));
116 btree_set.insert(create_sample_product(3, "Bookshelf", 149, "Furniture"));
117
118 let btree_vec: Vec<Product> = btree_set.iter().cloned().collect();
119 let btree_query = Query::new(&btree_vec);
120 println!(" BTreeSet: {} total items (sorted order!)", btree_query.count());
121
122 // BTreeSet items are in sorted order
123 for (i, item) in btree_vec.iter().take(3).enumerate() {
124 println!(" {}. {} (ID: {})", i + 1, item.name, item.id);
125 }
126
127 // ============================================================================
128 // CONTAINER 5: HashMap<K, V> - Query Values
129 // ============================================================================
130 println!("\n═══════════════════════════════════════════════════════════════");
131 println!("Container 5: HashMap<K, V> - Querying values");
132 println!("═══════════════════════════════════════════════════════════════\n");
133
134 let mut map_products = HashMap::new();
135 map_products.insert("prod1", create_sample_product(1, "Speaker", 199, "Electronics"));
136 map_products.insert("prod2", create_sample_product(2, "Headphones", 149, "Electronics"));
137 map_products.insert("prod3", create_sample_product(3, "Ottoman", 249, "Furniture"));
138
139 // Query HashMap values (convert to owned Vec)
140 let map_vec: Vec<Product> = map_products.values().cloned().collect();
141 let map_query = Query::new(&map_vec)
142 .where_(Product::category_r(), |cat| cat == "Electronics");
143 let electronics = map_query.all();
144 println!(" HashMap: {} electronics", electronics.len());
145
146 // ============================================================================
147 // CONTAINER 6: BTreeMap<K, V> - Query Values
148 // ============================================================================
149 println!("\n═══════════════════════════════════════════════════════════════");
150 println!("Container 6: BTreeMap<K, V> - Querying values");
151 println!("═══════════════════════════════════════════════════════════════\n");
152
153 let mut btree_map = BTreeMap::new();
154 btree_map.insert(1, create_sample_product(1, "Router", 89, "Electronics"));
155 btree_map.insert(2, create_sample_product(2, "Switch", 129, "Electronics"));
156 btree_map.insert(3, create_sample_product(3, "Sofa", 899, "Furniture"));
157
158 let btree_map_vec: Vec<Product> = btree_map.values().cloned().collect();
159 let btree_map_query = Query::new(&btree_map_vec);
160 let avg_price = btree_map_query.sum(Product::price_r()) as f64 / btree_map.len() as f64;
161 println!(" BTreeMap: Average price ${:.2}", avg_price);
162
163 // ============================================================================
164 // CONTAINER 7: Arrays [T; N]
165 // ============================================================================
166 println!("\n═══════════════════════════════════════════════════════════════");
167 println!("Container 7: Arrays [T; N]");
168 println!("═══════════════════════════════════════════════════════════════\n");
169
170 let array_products = [
171 create_sample_product(1, "USB Cable", 15, "Electronics"),
172 create_sample_product(2, "HDMI Cable", 25, "Electronics"),
173 create_sample_product(3, "Power Strip", 35, "Electronics"),
174 ];
175
176 // Query array directly (as slice)
177 let array_query = Query::new(&array_products);
178 let total = array_query.sum(Product::price_r());
179 println!(" Array: Total value ${}", total);
180
181 // Lazy on array
182 let lazy_array: Vec<_> = LazyQuery::new(&array_products)
183 .where_(Product::price_r(), |&p| p > 20)
184 .collect();
185 println!(" Array (lazy): {} items over $20", lazy_array.len());
186
187 // ============================================================================
188 // CONTAINER 8: LinkedList<T>
189 // ============================================================================
190 println!("\n═══════════════════════════════════════════════════════════════");
191 println!("Container 8: LinkedList<T>");
192 println!("═══════════════════════════════════════════════════════════════\n");
193
194 let mut list_products = LinkedList::new();
195 list_products.push_back(create_sample_product(1, "SSD", 159, "Electronics"));
196 list_products.push_back(create_sample_product(2, "HDD", 79, "Electronics"));
197
198 let list_vec: Vec<Product> = list_products.iter().cloned().collect();
199 let list_query = Query::new(&list_vec);
200 println!(" LinkedList: {} items", list_query.count());
201
202 // ============================================================================
203 // CONTAINER 9: Option<T> and Result<T, E>
204 // ============================================================================
205 println!("\n═══════════════════════════════════════════════════════════════");
206 println!("Container 9: Option<T> and Result<T, E>");
207 println!("═══════════════════════════════════════════════════════════════\n");
208
209 let maybe_product = Some(create_sample_product(1, "Mystery Box", 99, "Special"));
210
211 if let Some(ref product) = maybe_product {
212 let option_query = Query::new(std::slice::from_ref(product));
213 println!(" Option (Some): {} items", option_query.count());
214 }
215
216 let none_product: Option<Product> = None;
217 let none_count = none_product.iter().count();
218 println!(" Option (None): {} items", none_count);
219
220 // ============================================================================
221 // Summary
222 // ============================================================================
223 println!("\n╔════════════════════════════════════════════════════════════════╗");
224 println!("║ Supported Containers Summary ║");
225 println!("╚════════════════════════════════════════════════════════════════╝\n");
226
227 println!("✅ Supported container types:");
228 println!(" • Vec<T> - Standard vector");
229 println!(" • &[T] - Slices");
230 println!(" • [T; N] - Fixed-size arrays");
231 println!(" • VecDeque<T> - Double-ended queue");
232 println!(" • LinkedList<T> - Doubly-linked list");
233 println!(" • HashSet<T> - Unordered set");
234 println!(" • BTreeSet<T> - Ordered set");
235 println!(" • HashMap<K, V> - Query values");
236 println!(" • BTreeMap<K, V> - Query values (sorted)");
237 println!(" • Option<T> - 0 or 1 item");
238 println!(" • Result<T, E> - 0 or 1 item\n");
239
240 println!("📝 Usage patterns:");
241 println!(" • Direct: Query::new(&container) for Vec, slices, arrays");
242 println!(" • Convert: Collect to Vec for Sets and Maps");
243 println!(" • Lazy: LazyQuery::new(&slice) for any slice\n");
244
245 println!("💡 Tips:");
246 println!(" • Vec/slice: Direct support, most efficient");
247 println!(" • Sets: Iterate to Vec, then query");
248 println!(" • Maps: Use .values().collect() to query values");
249 println!(" • VecDeque: Use .as_slices() for zero-copy");
250 println!(" • For custom types: Implement Queryable trait\n");
251
252 println!("✓ Container support demo complete!\n");
253}230fn main() {
231 println!("\n╔════════════════════════════════════════════════════════════════╗");
232 println!("║ Custom Queryable Implementation Demo ║");
233 println!("╚════════════════════════════════════════════════════════════════╝\n");
234
235 // ============================================================================
236 // DEMO 1: PaginatedCollection
237 // ============================================================================
238 println!("═══════════════════════════════════════════════════════════════");
239 println!("Demo 1: PaginatedCollection (custom container)");
240 println!("═══════════════════════════════════════════════════════════════\n");
241
242 let mut paginated = PaginatedCollection::new(3); // 3 items per page
243
244 paginated.add(create_sample_product(1, "Laptop", 999.0, "Electronics", true));
245 paginated.add(create_sample_product(2, "Mouse", 29.0, "Electronics", true));
246 paginated.add(create_sample_product(3, "Keyboard", 129.0, "Electronics", true));
247 paginated.add(create_sample_product(4, "Desk", 299.0, "Furniture", true));
248 paginated.add(create_sample_product(5, "Chair", 199.0, "Furniture", false));
249
250 println!(" Created paginated collection:");
251 println!(" Total items: {}", paginated.total_items());
252 println!(" Pages: {}", paginated.pages.len());
253
254 // Now we can query it using the Queryable trait!
255 // Collect to owned Vec for querying
256 let items: Vec<Product> = paginated.query_iter().cloned().collect();
257 let query = Query::new(&items)
258 .where_(Product::category_r(), |cat| cat == "Electronics");
259 let electronics = query.all();
260
261 println!("\n Querying paginated collection:");
262 println!(" Electronics found: {}", electronics.len());
263 for product in electronics {
264 println!(" • {}: ${:.2}", product.name, product.price);
265 }
266
267 // ============================================================================
268 // DEMO 2: CircularBuffer
269 // ============================================================================
270 println!("\n═══════════════════════════════════════════════════════════════");
271 println!("Demo 2: CircularBuffer (fixed capacity)");
272 println!("═══════════════════════════════════════════════════════════════\n");
273
274 let mut circular = CircularBuffer::new(3); // Capacity: 3
275
276 circular.push(create_sample_product(1, "Product 1", 100.0, "A", true));
277 circular.push(create_sample_product(2, "Product 2", 200.0, "B", true));
278 circular.push(create_sample_product(3, "Product 3", 300.0, "C", true));
279 circular.push(create_sample_product(4, "Product 4", 400.0, "D", true)); // Pushes out Product 1
280
281 println!(" Circular buffer (capacity 3, added 4 items):");
282 println!(" Current size: {}", circular.len());
283
284 // Query the circular buffer
285 let circ_items: Vec<Product> = circular.query_iter().cloned().collect();
286 let circ_query = Query::new(&circ_items);
287 let avg_price = circ_query.avg(Product::price_r()).unwrap_or(0.0);
288
289 println!("\n Querying circular buffer:");
290 println!(" Average price: ${:.2}", avg_price);
291 println!(" Items:");
292 for (i, product) in circ_items.iter().enumerate() {
293 println!(" {}. {}: ${:.2}", i + 1, product.name, product.price);
294 }
295
296 // ============================================================================
297 // DEMO 3: FilteredStorage
298 // ============================================================================
299 println!("\n═══════════════════════════════════════════════════════════════");
300 println!("Demo 3: FilteredStorage (auto-filtering container)");
301 println!("═══════════════════════════════════════════════════════════════\n");
302
303 let mut filtered = FilteredStorage::new(|p: &Product| p.price < 200.0);
304
305 println!(" FilteredStorage (only accepts items < $200):");
306 println!(" Adding Laptop ($999): {}", filtered.add(create_sample_product(1, "Laptop", 999.0, "Electronics", true)));
307 println!(" Adding Mouse ($29): {}", filtered.add(create_sample_product(2, "Mouse", 29.0, "Electronics", true)));
308 println!(" Adding Keyboard ($129): {}", filtered.add(create_sample_product(3, "Keyboard", 129.0, "Electronics", true)));
309 println!(" Total stored: {}", filtered.len());
310
311 // Query the filtered storage
312 let filt_items: Vec<Product> = filtered.query_iter().cloned().collect();
313 let filt_query = Query::new(&filt_items)
314 .where_(Product::in_stock_r(), |&v| v);
315 let in_stock = filt_query.all();
316
317 println!("\n Querying filtered storage:");
318 println!(" In stock items: {}", in_stock.len());
319
320 // ============================================================================
321 // DEMO 4: CategoryIndex
322 // ============================================================================
323 println!("\n═══════════════════════════════════════════════════════════════");
324 println!("Demo 4: CategoryIndex (indexed by category)");
325 println!("═══════════════════════════════════════════════════════════════\n");
326
327 let mut category_index = CategoryIndex::new();
328
329 category_index.add("Electronics".to_string(), create_sample_product(1, "Monitor", 349.0, "Electronics", true));
330 category_index.add("Electronics".to_string(), create_sample_product(2, "Webcam", 79.0, "Electronics", true));
331 category_index.add("Furniture".to_string(), create_sample_product(3, "Desk", 299.0, "Furniture", true));
332 category_index.add("Furniture".to_string(), create_sample_product(4, "Lamp", 39.0, "Furniture", true));
333
334 println!(" CategoryIndex:");
335 println!(" Categories: {:?}", category_index.categories());
336 println!(" Total items: {}", category_index.total_items());
337
338 // Query across all categories
339 let idx_items: Vec<Product> = category_index.query_iter().cloned().collect();
340 let idx_query = Query::new(&idx_items);
341 let expensive = idx_query
342 .where_(Product::price_r(), |&p| p > 100.0);
343 let expensive_items = expensive.all();
344
345 println!("\n Querying category index:");
346 println!(" Expensive items (>$100): {}", expensive_items.len());
347 for product in expensive_items {
348 println!(" • {}: ${:.2} ({})", product.name, product.price, product.category);
349 }
350
351 // ============================================================================
352 // DEMO 5: LazyLoader
353 // ============================================================================
354 println!("\n═══════════════════════════════════════════════════════════════");
355 println!("Demo 5: LazyLoader (simulated lazy loading)");
356 println!("═══════════════════════════════════════════════════════════════\n");
357
358 let loader = LazyLoader::new(vec![
359 create_sample_product(1, "Item 1", 50.0, "A", true),
360 create_sample_product(2, "Item 2", 150.0, "B", true),
361 create_sample_product(3, "Item 3", 250.0, "C", true),
362 ]);
363
364 println!(" LazyLoader:");
365 println!(" Total available: {}", loader.total_count());
366 println!(" Currently loaded: {}", loader.loaded_count());
367
368 // Query loaded items
369 let loader_items: Vec<Product> = loader.query_iter().cloned().collect();
370 let loader_query = Query::new(&loader_items);
371 let total_value = loader_query.sum(Product::price_r());
372
373 println!("\n Querying lazy loader:");
374 println!(" Total value: ${:.2}", total_value);
375
376 // ============================================================================
377 // DEMO 6: Custom Container with LazyQuery
378 // ============================================================================
379 println!("\n═══════════════════════════════════════════════════════════════");
380 println!("Demo 6: Using LazyQuery with custom containers");
381 println!("═══════════════════════════════════════════════════════════════\n");
382
383 let mut circular = CircularBuffer::new(5);
384 for i in 1..=10 {
385 circular.push(create_sample_product(
386 i,
387 &format!("Product {}", i),
388 i as f64 * 50.0,
389 if i % 2 == 0 { "Even" } else { "Odd" },
390 true,
391 ));
392 }
393
394 println!(" Circular buffer (capacity 5, added 10 items):");
395 println!(" Current size: {}", circular.len());
396
397 // Use LazyQuery for early termination!
398 let circ_vec: Vec<Product> = circular.query_iter().cloned().collect();
399 let first_expensive = LazyQuery::new(&circ_vec)
400 .where_(Product::price_r(), |&p| p > 300.0)
401 .first();
402
403 if let Some(product) = first_expensive {
404 println!("\n First expensive item (lazy query):");
405 println!(" {}: ${:.2}", product.name, product.price);
406 }
407
408 // ============================================================================
409 // DEMO 7: Implementing Queryable for Wrapper Types
410 // ============================================================================
411 println!("\n═══════════════════════════════════════════════════════════════");
412 println!("Demo 7: Queryable for wrapper types");
413 println!("═══════════════════════════════════════════════════════════════\n");
414
415 /// A simple wrapper around Vec with metadata
416 struct VersionedCollection<T> {
417 items: Vec<T>,
418 version: u32,
419 last_modified: String,
420 }
421
422 impl<T> Queryable<T> for VersionedCollection<T> {
423 fn query_iter(&self) -> Box<dyn Iterator<Item = &T> + '_> {
424 Box::new(self.items.iter())
425 }
426 }
427
428 let versioned = VersionedCollection {
429 items: vec![
430 create_sample_product(1, "V1 Product", 99.0, "Test", true),
431 create_sample_product(2, "V2 Product", 199.0, "Test", true),
432 ],
433 version: 2,
434 last_modified: "2025-10-11".to_string(),
435 };
436
437 println!(" VersionedCollection:");
438 println!(" Version: {}", versioned.version);
439 println!(" Last modified: {}", versioned.last_modified);
440
441 let versioned_items: Vec<Product> = versioned.query_iter().cloned().collect();
442 let query = Query::new(&versioned_items);
443 println!(" Items: {}", query.count());
444
445 // ============================================================================
446 // DEMO 8: Real-World Example - Cache with TTL
447 // ============================================================================
448 println!("\n═══════════════════════════════════════════════════════════════");
449 println!("Demo 8: Cache container (real-world example)");
450 println!("═══════════════════════════════════════════════════════════════\n");
451
452 use std::time::{Duration, SystemTime};
453
454 struct CachedItem<T> {
455 item: T,
456 inserted_at: SystemTime,
457 ttl: Duration,
458 }
459
460 struct Cache<T> {
461 items: Vec<CachedItem<T>>,
462 }
463
464 impl<T> Cache<T> {
465 fn new() -> Self {
466 Self { items: Vec::new() }
467 }
468
469 fn insert(&mut self, item: T, ttl: Duration) {
470 self.items.push(CachedItem {
471 item,
472 inserted_at: SystemTime::now(),
473 ttl,
474 });
475 }
476
477 fn valid_items(&self) -> Vec<&T> {
478 let now = SystemTime::now();
479 self.items
480 .iter()
481 .filter(|cached| {
482 now.duration_since(cached.inserted_at)
483 .map_or(false, |elapsed| elapsed < cached.ttl)
484 })
485 .map(|cached| &cached.item)
486 .collect()
487 }
488 }
489
490 // Implement Queryable to query only valid (non-expired) items
491 impl<T> Queryable<T> for Cache<T> {
492 fn query_iter(&self) -> Box<dyn Iterator<Item = &T> + '_> {
493 let now = SystemTime::now();
494 Box::new(
495 self.items
496 .iter()
497 .filter(move |cached| {
498 now.duration_since(cached.inserted_at)
499 .map_or(false, |elapsed| elapsed < cached.ttl)
500 })
501 .map(|cached| &cached.item),
502 )
503 }
504 }
505
506 let mut cache = Cache::new();
507 cache.insert(create_sample_product(1, "Cached Item 1", 100.0, "A", true), Duration::from_secs(60));
508 cache.insert(create_sample_product(2, "Cached Item 2", 200.0, "B", true), Duration::from_secs(60));
509
510 let valid = cache.valid_items();
511 println!(" Cache:");
512 println!(" Total items: {}", cache.items.len());
513 println!(" Valid items: {}", valid.len());
514
515 // Query the cache
516 let cache_items: Vec<Product> = cache.query_iter().cloned().collect();
517 let cache_query = Query::new(&cache_items);
518 println!(" Queryable items: {}", cache_query.count());
519
520 // ============================================================================
521 // Summary
522 // ============================================================================
523 println!("\n╔════════════════════════════════════════════════════════════════╗");
524 println!("║ Summary: Implementing Queryable ║");
525 println!("╚════════════════════════════════════════════════════════════════╝\n");
526
527 println!("✅ How to make any container queryable:\n");
528 println!(" 1. Implement the Queryable<T> trait:");
529 println!(" ```rust");
530 println!(" impl<T> Queryable<T> for MyContainer<T> {{");
531 println!(" fn query_iter(&self) -> Box<dyn Iterator<Item = &T> + '_> {{");
532 println!(" Box::new(self.items.iter())");
533 println!(" }}");
534 println!(" }}");
535 println!(" ```\n");
536
537 println!(" 2. Convert to Vec or slice for querying:");
538 println!(" ```rust");
539 println!(" let items: Vec<&Product> = container.query_iter().collect();");
540 println!(" let query = Query::new(&items);");
541 println!(" ```\n");
542
543 println!(" 3. Now use all query operations:");
544 println!(" ```rust");
545 println!(" let results = query.where_(...).all();");
546 println!(" let count = query.count();");
547 println!(" let total = query.sum(field);");
548 println!(" ```\n");
549
550 println!("📝 Custom containers demonstrated:");
551 println!(" • PaginatedCollection - Items stored in pages");
552 println!(" • CircularBuffer - Fixed-capacity FIFO buffer");
553 println!(" • FilteredStorage - Auto-filtering container");
554 println!(" • CategoryIndex - Indexed by category");
555 println!(" • LazyLoader - Simulated lazy loading");
556 println!(" • VersionedCollection - Wrapper with metadata");
557 println!(" • Cache - TTL-based cache\n");
558
559 println!("💡 Use cases:");
560 println!(" • Database result wrappers");
561 println!(" • Custom data structures");
562 println!(" • Specialized collections");
563 println!(" • Caches and buffers");
564 println!(" • Event streams");
565 println!(" • Any container that holds items!\n");
566
567 println!("✓ Custom Queryable demo complete!\n");
568}84fn main() {
85 let employees = create_employees();
86 let departments = create_departments();
87 let projects = create_projects();
88
89 println!("\n╔════════════════════════════════════════════════════════════════════════╗");
90 println!("║ SQL vs Rust Query Builder Comparison ║");
91 println!("║ Demonstrating equivalent operations ║");
92 println!("╚════════════════════════════════════════════════════════════════════════╝");
93
94 // ============================================================================
95 // EXAMPLE 1: Simple SELECT with WHERE
96 // ============================================================================
97 print_separator("Example 1: SELECT with WHERE clause");
98 print_query(
99 "SELECT * FROM employees WHERE department = 'Engineering';",
100 "Filter employees by department"
101 );
102
103 let eng_query = Query::new(&employees)
104 .where_(Employee::department_r(), |dept| dept == "Engineering");
105 let engineering_employees = eng_query.all();
106
107 for emp in &engineering_employees {
108 println!(" ID: {}, Name: {}, Salary: ${:.2}", emp.id, emp.name, emp.salary);
109 }
110 println!("\nRust Query Builder:");
111 println!("Query::new(&employees)");
112 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\")");
113 println!(" .all()");
114 println!("✓ Found {} employees", engineering_employees.len());
115
116 // ============================================================================
117 // EXAMPLE 2: SELECT specific columns
118 // ============================================================================
119 print_separator("Example 2: SELECT specific columns (Projection)");
120 print_query(
121 "SELECT name FROM employees WHERE salary > 80000;",
122 "Get names of high-earning employees"
123 );
124
125 let high_earners = Query::new(&employees)
126 .where_(Employee::salary_r(), |&salary| salary > 80000.0)
127 .select(Employee::name_r());
128
129 for name in &high_earners {
130 println!(" {}", name);
131 }
132 println!("\nRust Query Builder:");
133 println!("Query::new(&employees)");
134 println!(" .where_(Employee::salary_r(), |&salary| salary > 80000.0)");
135 println!(" .select(Employee::name_r())");
136 println!("✓ Found {} employees", high_earners.len());
137
138 // ============================================================================
139 // EXAMPLE 3: COUNT
140 // ============================================================================
141 print_separator("Example 3: COUNT aggregation");
142 print_query(
143 "SELECT COUNT(*) FROM employees WHERE age < 30;",
144 "Count young employees"
145 );
146
147 let young_count = Query::new(&employees)
148 .where_(Employee::age_r(), |&age| age < 30)
149 .count();
150
151 println!(" Count: {}", young_count);
152 println!("\nRust Query Builder:");
153 println!("Query::new(&employees)");
154 println!(" .where_(Employee::age_r(), |&age| age < 30)");
155 println!(" .count()");
156 println!("✓ Result: {}", young_count);
157
158 // ============================================================================
159 // EXAMPLE 4: SUM, AVG, MIN, MAX
160 // ============================================================================
161 print_separator("Example 4: Aggregate functions (SUM, AVG, MIN, MAX)");
162 print_query(
163 "SELECT \n\
164 SUM(salary) as total_salary,\n\
165 AVG(salary) as avg_salary,\n\
166 MIN(salary) as min_salary,\n\
167 MAX(salary) as max_salary\n\
168 FROM employees WHERE department = 'Engineering';",
169 "Engineering department salary statistics"
170 );
171
172 let eng_query = Query::new(&employees)
173 .where_(Employee::department_r(), |dept| dept == "Engineering");
174
175 let total = eng_query.sum(Employee::salary_r());
176 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
177 let min = eng_query.min_float(Employee::salary_r()).unwrap_or(0.0);
178 let max = eng_query.max_float(Employee::salary_r()).unwrap_or(0.0);
179
180 println!(" Total Salary: ${:.2}", total);
181 println!(" Avg Salary: ${:.2}", avg);
182 println!(" Min Salary: ${:.2}", min);
183 println!(" Max Salary: ${:.2}", max);
184
185 println!("\nRust Query Builder:");
186 println!("let query = Query::new(&employees)");
187 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\");");
188 println!("query.sum(Employee::salary_r()) // ${:.2}", total);
189 println!("query.avg(Employee::salary_r()) // ${:.2}", avg);
190 println!("query.min_float(Employee::salary_r()) // ${:.2}", min);
191 println!("query.max_float(Employee::salary_r()) // ${:.2}", max);
192
193 // ============================================================================
194 // EXAMPLE 5: GROUP BY with aggregation
195 // ============================================================================
196 print_separator("Example 5: GROUP BY with aggregation");
197 print_query(
198 "SELECT \n\
199 department,\n\
200 COUNT(*) as emp_count,\n\
201 AVG(salary) as avg_salary\n\
202 FROM employees\n\
203 GROUP BY department;",
204 "Statistics by department"
205 );
206
207 let by_dept = Query::new(&employees).group_by(Employee::department_r());
208
209 for (dept, emps) in &by_dept {
210 let dept_query = Query::new(emps);
211 let count = emps.len();
212 let avg_sal = dept_query.avg(Employee::salary_r()).unwrap_or(0.0);
213 println!(" {}: {} employees, avg salary ${:.2}", dept, count, avg_sal);
214 }
215
216 println!("\nRust Query Builder:");
217 println!("let by_dept = Query::new(&employees).group_by(Employee::department_r());");
218 println!("for (dept, emps) in &by_dept {{");
219 println!(" let dept_query = Query::new(emps);");
220 println!(" dept_query.avg(Employee::salary_r())");
221 println!("}}");
222
223 // ============================================================================
224 // EXAMPLE 6: ORDER BY
225 // ============================================================================
226 print_separator("Example 6: ORDER BY");
227 print_query(
228 "SELECT name, salary FROM employees\n\
229 WHERE department = 'Sales'\n\
230 ORDER BY salary DESC;",
231 "Sales employees ordered by salary (descending)"
232 );
233
234 let sales_sorted = Query::new(&employees)
235 .where_(Employee::department_r(), |dept| dept == "Sales")
236 .order_by_float_desc(Employee::salary_r());
237
238 for emp in &sales_sorted {
239 println!(" {}: ${:.2}", emp.name, emp.salary);
240 }
241
242 println!("\nRust Query Builder:");
243 println!("Query::new(&employees)");
244 println!(" .where_(Employee::department_r(), |dept| dept == \"Sales\")");
245 println!(" .order_by_float_desc(Employee::salary_r())");
246
247 // ============================================================================
248 // EXAMPLE 7: Multiple WHERE conditions (AND)
249 // ============================================================================
250 print_separator("Example 7: Multiple WHERE conditions (AND)");
251 print_query(
252 "SELECT * FROM employees\n\
253 WHERE salary > 70000 AND age < 35;",
254 "High-earning young employees"
255 );
256
257 let filter_query = Query::new(&employees)
258 .where_(Employee::salary_r(), |&salary| salary > 70000.0)
259 .where_(Employee::age_r(), |&age| age < 35);
260 let filtered = filter_query.all();
261
262 for emp in &filtered {
263 println!(" {}: Age {}, Salary ${:.2}", emp.name, emp.age, emp.salary);
264 }
265
266 println!("\nRust Query Builder:");
267 println!("Query::new(&employees)");
268 println!(" .where_(Employee::salary_r(), |&salary| salary > 70000.0)");
269 println!(" .where_(Employee::age_r(), |&age| age < 35)");
270 println!(" .all()");
271 println!("✓ Found {} employees", filtered.len());
272
273 // ============================================================================
274 // EXAMPLE 8: LIMIT (TOP N)
275 // ============================================================================
276 print_separator("Example 8: LIMIT / TOP N");
277 print_query(
278 "SELECT TOP 3 name, salary FROM employees\n\
279 ORDER BY salary DESC;",
280 "Top 3 highest paid employees"
281 );
282
283 let top_earners = Query::new(&employees)
284 .order_by_float_desc(Employee::salary_r());
285
286 for (i, emp) in top_earners.iter().take(3).enumerate() {
287 println!(" {}. {}: ${:.2}", i + 1, emp.name, emp.salary);
288 }
289
290 println!("\nRust Query Builder:");
291 println!("Query::new(&employees)");
292 println!(" .order_by_float_desc(Employee::salary_r())");
293 println!(" .into_iter().take(3)");
294
295 // ============================================================================
296 // EXAMPLE 9: OFFSET and LIMIT (Pagination)
297 // ============================================================================
298 print_separator("Example 9: OFFSET and LIMIT (Pagination)");
299 print_query(
300 "SELECT name FROM employees\n\
301 ORDER BY name\n\
302 LIMIT 3 OFFSET 3;",
303 "Page 2 of employee names (3 per page)"
304 );
305
306 let page_2 = Query::new(&employees)
307 .order_by(Employee::name_r())
308 .into_iter()
309 .skip(3)
310 .take(3)
311 .collect::<Vec<_>>();
312
313 for emp in &page_2 {
314 println!(" {}", emp.name);
315 }
316
317 println!("\nRust Query Builder:");
318 println!("Query::new(&employees)");
319 println!(" .order_by(Employee::name_r())");
320 println!(" .into_iter().skip(3).take(3)");
321
322 // ============================================================================
323 // EXAMPLE 10: INNER JOIN
324 // ============================================================================
325 print_separator("Example 10: INNER JOIN");
326 print_query(
327 "SELECT e.name, d.name as dept_name, d.budget\n\
328 FROM employees e\n\
329 INNER JOIN departments d ON e.department = d.name;",
330 "Employees with their department info"
331 );
332
333 let emp_dept = JoinQuery::new(&employees, &departments).inner_join(
334 Employee::department_r(),
335 Department::name_r(),
336 |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget),
337 );
338
339 for (emp_name, dept_name, budget) in emp_dept.iter().take(5) {
340 println!(" {} works in {} (Budget: ${:.0})", emp_name, dept_name, budget);
341 }
342 println!(" ... (showing first 5)");
343
344 println!("\nRust Query Builder:");
345 println!("JoinQuery::new(&employees, &departments).inner_join(");
346 println!(" Employee::department_r(),");
347 println!(" Department::name_r(),");
348 println!(" |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget)");
349 println!(")");
350 println!("✓ Found {} matches", emp_dept.len());
351
352 // ============================================================================
353 // EXAMPLE 11: GROUP BY with HAVING equivalent
354 // ============================================================================
355 print_separator("Example 11: GROUP BY with filtering (HAVING equivalent)");
356 print_query(
357 "SELECT city, COUNT(*) as emp_count, AVG(salary) as avg_salary\n\
358 FROM employees\n\
359 GROUP BY city\n\
360 HAVING COUNT(*) > 1;",
361 "Cities with multiple employees"
362 );
363
364 let by_city = Query::new(&employees).group_by(Employee::city_r());
365 let mut city_stats: Vec<_> = by_city
366 .iter()
367 .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent
368 .map(|(city, emps)| {
369 let avg_sal = Query::new(emps).avg(Employee::salary_r()).unwrap_or(0.0);
370 (city.clone(), emps.len(), avg_sal)
371 })
372 .collect();
373
374 city_stats.sort_by(|a, b| b.1.cmp(&a.1)); // Sort by count
375
376 for (city, count, avg_sal) in &city_stats {
377 println!(" {}: {} employees, avg salary ${:.2}", city, count, avg_sal);
378 }
379
380 println!("\nRust Query Builder:");
381 println!("let by_city = Query::new(&employees).group_by(Employee::city_r());");
382 println!("by_city.iter()");
383 println!(" .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent");
384 println!(" .map(|(city, emps)| {{");
385 println!(" let avg = Query::new(emps).avg(Employee::salary_r());");
386 println!(" (city, emps.len(), avg)");
387 println!(" }})");
388
389 // ============================================================================
390 // EXAMPLE 12: Complex query with multiple operations
391 // ============================================================================
392 print_separator("Example 12: Complex multi-operation query");
393 print_query(
394 "SELECT name, salary, age\n\
395 FROM employees\n\
396 WHERE department IN ('Engineering', 'Sales')\n\
397 AND salary BETWEEN 80000 AND 100000\n\
398 AND age >= 30\n\
399 ORDER BY salary DESC;",
400 "Experienced mid-to-senior level employees in core departments"
401 );
402
403 let complex_query = Query::new(&employees)
404 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
405 .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)
406 .where_(Employee::age_r(), |&age| age >= 30)
407 .order_by_float_desc(Employee::salary_r());
408
409 for emp in &complex_query {
410 println!(" {}: Age {}, {} dept, ${:.2}", emp.name, emp.age, emp.department, emp.salary);
411 }
412
413 println!("\nRust Query Builder:");
414 println!("Query::new(&employees)");
415 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\" || dept == \"Sales\")");
416 println!(" .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)");
417 println!(" .where_(Employee::age_r(), |&age| age >= 30)");
418 println!(" .order_by_float_desc(Employee::salary_r())");
419 println!("✓ Found {} employees", complex_query.len());
420
421 // ============================================================================
422 // EXAMPLE 13: Three-table JOIN
423 // ============================================================================
424 print_separator("Example 13: Three-table JOIN");
425 print_query(
426 "SELECT p.name as project, d.name as department, d.location\n\
427 FROM projects p\n\
428 INNER JOIN departments d ON p.department_id = d.id;",
429 "Projects with their department details"
430 );
431
432 let proj_dept = JoinQuery::new(&projects, &departments).inner_join(
433 Project::department_id_r(),
434 Department::id_r(),
435 |proj, dept| {
436 (proj.name.clone(), dept.name.clone(), dept.location.clone(), proj.budget)
437 },
438 );
439
440 for (proj_name, dept_name, location, budget) in &proj_dept {
441 println!(" {}: {} dept in {} (${:.0})", proj_name, dept_name, location, budget);
442 }
443
444 println!("\nRust Query Builder:");
445 println!("JoinQuery::new(&projects, &departments).inner_join(");
446 println!(" Project::department_id_r(),");
447 println!(" Department::id_r(),");
448 println!(" |proj, dept| (proj.name, dept.name, dept.location, proj.budget)");
449 println!(")");
450
451 // ============================================================================
452 // EXAMPLE 14: Subquery equivalent (using intermediate results)
453 // ============================================================================
454 print_separator("Example 14: Subquery equivalent");
455 print_query(
456 "SELECT * FROM employees\n\
457 WHERE salary > (SELECT AVG(salary) FROM employees);",
458 "Employees earning above average"
459 );
460
461 let avg_salary = Query::new(&employees)
462 .avg(Employee::salary_r())
463 .unwrap_or(0.0);
464
465 let above_avg_query = Query::new(&employees)
466 .where_(Employee::salary_r(), move |&sal| sal > avg_salary);
467 let above_avg = above_avg_query.all();
468
469 println!(" Average salary: ${:.2}", avg_salary);
470 for emp in &above_avg {
471 println!(" {}: ${:.2} ({:.1}% above average)",
472 emp.name, emp.salary, ((emp.salary - avg_salary) / avg_salary * 100.0));
473 }
474
475 println!("\nRust Query Builder:");
476 println!("let avg = Query::new(&employees).avg(Employee::salary_r()).unwrap_or(0.0);");
477 println!("Query::new(&employees)");
478 println!(" .where_(Employee::salary_r(), |&sal| sal > avg)");
479 println!(" .all()");
480 println!("✓ Found {} employees above average", above_avg.len());
481
482 // ============================================================================
483 // EXAMPLE 15: Advanced aggregation (revenue calculation)
484 // ============================================================================
485 print_separator("Example 15: Advanced aggregation");
486 print_query(
487 "SELECT \n\
488 d.name,\n\
489 d.budget as dept_budget,\n\
490 SUM(p.budget) as total_project_budget,\n\
491 (d.budget - SUM(p.budget)) as remaining_budget\n\
492 FROM departments d\n\
493 LEFT JOIN projects p ON d.id = p.department_id\n\
494 GROUP BY d.name, d.budget;",
495 "Department budget utilization"
496 );
497
498 // Join departments with projects
499 let dept_projects = JoinQuery::new(&departments, &projects).left_join(
500 Department::id_r(),
501 Project::department_id_r(),
502 |dept, proj| (dept.clone(), proj.map(|p| p.clone())),
503 );
504
505 // Aggregate by department
506 let mut dept_budget_map: HashMap<String, (f64, Vec<f64>)> = HashMap::new();
507 for (dept, proj) in dept_projects {
508 let entry = dept_budget_map
509 .entry(dept.name.clone())
510 .or_insert((dept.budget, Vec::new()));
511 if let Some(p) = proj {
512 entry.1.push(p.budget);
513 }
514 }
515
516 for (dept_name, (total_budget, project_budgets)) in dept_budget_map.iter() {
517 let used: f64 = project_budgets.iter().sum();
518 let remaining = total_budget - used;
519 println!(" {}: Budget ${:.0}, Used ${:.0}, Remaining ${:.0} ({:.1}% utilized)",
520 dept_name, total_budget, used, remaining, (used / total_budget * 100.0));
521 }
522
523 println!("\nRust Query Builder:");
524 println!("let dept_projects = JoinQuery::new(&departments, &projects)");
525 println!(" .left_join(Department::id_r(), Project::department_id_r(), ...)");
526 println!("// Then aggregate using HashMap");
527
528 // ============================================================================
529 // Summary
530 // ============================================================================
531 print_separator("Summary");
532 println!("\n✓ All 15 SQL queries successfully replicated with Rust Query Builder!");
533 println!("\nDemonstrated equivalents for:");
534 println!(" • SELECT with WHERE");
535 println!(" • Projection (SELECT specific columns)");
536 println!(" • Aggregations (COUNT, SUM, AVG, MIN, MAX)");
537 println!(" • GROUP BY");
538 println!(" • ORDER BY");
539 println!(" • LIMIT and OFFSET");
540 println!(" • INNER JOIN and LEFT JOIN");
541 println!(" • Complex conditions (AND, OR, BETWEEN)");
542 println!(" • Subqueries");
543 println!(" • Multi-table operations");
544 println!("\n🎯 Type-safe, compile-time checked, and zero runtime overhead!");
545 println!();
546}Sourcepub fn avg(&self, path: KeyPaths<T, f64>) -> Option<f64>
pub fn avg(&self, path: KeyPaths<T, f64>) -> Option<f64>
Computes the average of a float field.
§Arguments
path- The key-path to the f64 field
§Example
let avg_price = query.avg(Product::price_r()).unwrap_or(0.0);Examples found in repository?
28fn main() {
29 println!("╔════════════════════════════════════════════════════════════╗");
30 println!("║ Query Builder Without Clone - Performance Optimization ║");
31 println!("╚════════════════════════════════════════════════════════════╝\n");
32
33 let employees = vec![
34 Employee {
35 id: 1,
36 name: "Alice".to_string(),
37 email: "alice@example.com".to_string(),
38 department: "Engineering".to_string(),
39 salary: 95000.0,
40 large_data: vec![0; 1000], // Large data - expensive to clone!
41 },
42 Employee {
43 id: 2,
44 name: "Bob".to_string(),
45 email: "bob@example.com".to_string(),
46 department: "Engineering".to_string(),
47 salary: 87000.0,
48 large_data: vec![0; 1000],
49 },
50 Employee {
51 id: 3,
52 name: "Carol".to_string(),
53 email: "carol@example.com".to_string(),
54 department: "Sales".to_string(),
55 salary: 75000.0,
56 large_data: vec![0; 1000],
57 },
58 ];
59
60 let departments = vec![
61 Department {
62 id: 1,
63 name: "Engineering".to_string(),
64 budget: 1000000.0,
65 },
66 Department {
67 id: 2,
68 name: "Sales".to_string(),
69 budget: 500000.0,
70 },
71 ];
72
73 println!("✅ Operations that DON'T require Clone:\n");
74
75 // 1. WHERE filtering - returns Vec<&T>
76 println!("1. WHERE filtering (returns references)");
77 let query = Query::new(&employees)
78 .where_(Employee::department_r(), |dept| dept == "Engineering");
79 let engineering = query.all();
80 println!(" Found {} engineering employees", engineering.len());
81 for emp in &engineering {
82 println!(" - {}: ${:.0}", emp.name, emp.salary);
83 }
84
85 // 2. COUNT - no cloning needed
86 println!("\n2. COUNT aggregation");
87 let count = Query::new(&employees)
88 .where_(Employee::salary_r(), |&sal| sal > 80000.0)
89 .count();
90 println!(" {} employees earn over $80k", count);
91
92 // 3. SELECT - only clones the selected field
93 println!("\n3. SELECT (only selected fields are cloned)");
94 let names: Vec<String> = Query::new(&employees)
95 .select(Employee::name_r());
96 println!(" Employee names: {:?}", names);
97
98 // 4. FIRST - returns Option<&T>
99 println!("\n4. FIRST (returns reference)");
100 let query = Query::new(&employees)
101 .where_(Employee::salary_r(), |&sal| sal > 90000.0);
102 if let Some(emp) = query.first() {
103 println!(" First high earner: {} (${:.0})", emp.name, emp.salary);
104 }
105
106 // 5. SUM/AVG aggregations - no cloning
107 println!("\n5. Aggregations (SUM/AVG)");
108 let eng_query = Query::new(&employees)
109 .where_(Employee::department_r(), |dept| dept == "Engineering");
110 let total = eng_query.sum(Employee::salary_r());
111 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
112 println!(" Engineering total: ${:.0}", total);
113 println!(" Engineering average: ${:.0}", avg);
114
115 // 6. MIN/MAX - no cloning
116 println!("\n6. MIN/MAX");
117 let min = Query::new(&employees).min_float(Employee::salary_r());
118 let max = Query::new(&employees).max_float(Employee::salary_r());
119 println!(" Salary range: ${:.0} - ${:.0}", min.unwrap(), max.unwrap());
120
121 // 7. LIMIT - returns Vec<&T>
122 println!("\n7. LIMIT (returns references)");
123 let query = Query::new(&employees);
124 let first_two = query.limit(2);
125 println!(" First 2 employees:");
126 for emp in &first_two {
127 println!(" - {}", emp.name);
128 }
129
130 // 8. SKIP/Pagination - returns Vec<&T>
131 println!("\n8. SKIP/Pagination (returns references)");
132 let query = Query::new(&employees);
133 let page_2 = query.skip(2).limit(1);
134 println!(" Page 2:");
135 for emp in &page_2 {
136 println!(" - {}", emp.name);
137 }
138
139 // 9. EXISTS - just checks
140 println!("\n9. EXISTS check");
141 let has_sales = Query::new(&employees)
142 .where_(Employee::department_r(), |dept| dept == "Sales")
143 .exists();
144 println!(" Has Sales employees: {}", has_sales);
145
146 // 10. JOIN - no Clone required on L or R!
147 println!("\n10. JOIN operations (no Clone required!)");
148 let results = JoinQuery::new(&employees, &departments)
149 .inner_join(
150 Employee::department_r(),
151 Department::name_r(),
152 |emp, dept| {
153 // Mapper only clones what it needs for the result
154 (emp.name.clone(), dept.budget)
155 },
156 );
157 println!(" Employee-Department pairs:");
158 for (name, budget) in &results {
159 println!(" - {} works in dept with ${:.0} budget", name, budget);
160 }
161
162 println!("\n╔════════════════════════════════════════════════════════════╗");
163 println!("║ Operations that REQUIRE Clone (only when needed) ║");
164 println!("╚════════════════════════════════════════════════════════════╝\n");
165
166 println!("⚠️ The following operations require Clone because they return owned Vec<T>:");
167 println!(" - order_by() / order_by_desc()");
168 println!(" - order_by_float() / order_by_float_desc()");
169 println!(" - group_by()");
170 println!("\n To use these, add #[derive(Clone)] to your struct:");
171 println!(" ```rust");
172 println!(" #[derive(Clone, Keypaths)] // Add Clone here");
173 println!(" struct Employee {{ ... }}");
174 println!(" ```");
175
176 println!("\n╔════════════════════════════════════════════════════════════╗");
177 println!("║ Performance Benefits ║");
178 println!("╚════════════════════════════════════════════════════════════╝\n");
179
180 println!("✅ Zero cloning for most operations");
181 println!("✅ Work with large structs efficiently");
182 println!("✅ No unnecessary memory allocations");
183 println!("✅ Only clone when you actually need owned data");
184 println!("✅ Pay for what you use");
185
186 println!("\n✓ Example complete! Most operations work without Clone.\n");
187}More examples
30fn main() {
31 println!("Testing documentation examples...\n");
32
33 // Example from README - Quick Start
34 println!("Test 1: README Quick Start Example");
35 {
36 let products = vec![
37 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
38 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
39 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
40 ];
41
42 let affordable_query = Query::new(&products)
43 .where_(Product::category_r(), |cat| cat == "Electronics")
44 .where_(Product::price_r(), |&price| price < 100.0);
45 let affordable_electronics = affordable_query.all();
46
47 println!(" Found {} affordable electronics ✅", affordable_electronics.len());
48 }
49
50 // Example from README - Filtering
51 println!("\nTest 2: Filtering Example");
52 {
53 let products = vec![
54 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
55 ];
56
57 let electronics_query = Query::new(&products)
58 .where_(Product::category_r(), |cat| cat == "Electronics");
59 let electronics = electronics_query.all();
60
61 println!(" Found {} electronics ✅", electronics.len());
62 }
63
64 // Example from README - Selecting
65 println!("\nTest 3: Selecting Fields Example");
66 {
67 let products = vec![
68 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
69 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
70 ];
71
72 let names: Vec<String> = Query::new(&products)
73 .select(Product::name_r());
74
75 println!(" Selected {} names ✅", names.len());
76 }
77
78 // Example from README - Ordering
79 println!("\nTest 4: Ordering Example");
80 {
81 let products = vec![
82 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
83 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
84 ];
85
86 let by_price = Query::new(&products).order_by_float(Product::price_r());
87 println!(" Ordered {} products ✅", by_price.len());
88 }
89
90 // Example from README - Aggregations
91 println!("\nTest 5: Aggregations Example");
92 {
93 let products = vec![
94 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
95 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
96 ];
97
98 let electronics_query = Query::new(&products)
99 .where_(Product::category_r(), |cat| cat == "Electronics");
100
101 let count = electronics_query.count();
102 let total_value: f64 = electronics_query.sum(Product::price_r());
103 let avg_price = electronics_query.avg(Product::price_r()).unwrap_or(0.0);
104
105 println!(" Count: {}, Total: ${:.2}, Avg: ${:.2} ✅", count, total_value, avg_price);
106 }
107
108 // Example from README - Grouping
109 println!("\nTest 6: Grouping Example");
110 {
111 let products = vec![
112 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
113 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
114 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
115 ];
116
117 let by_category = Query::new(&products).group_by(Product::category_r());
118 println!(" Grouped into {} categories ✅", by_category.len());
119 }
120
121 // Example from README - Pagination
122 println!("\nTest 7: Pagination Example");
123 {
124 let products = vec![
125 Product { id: 1, name: "P1".to_string(), price: 10.0, category: "A".to_string(), stock: 1, rating: 4.0 },
126 Product { id: 2, name: "P2".to_string(), price: 20.0, category: "A".to_string(), stock: 1, rating: 4.0 },
127 Product { id: 3, name: "P3".to_string(), price: 30.0, category: "A".to_string(), stock: 1, rating: 4.0 },
128 ];
129
130 let query = Query::new(&products);
131 let first_10 = query.limit(10);
132 let page_1 = query.skip(0).limit(10);
133
134 println!(" Limited to {} products ✅", first_10.len());
135 println!(" Page 1 has {} products ✅", page_1.len());
136 }
137
138 // Example from README - Join
139 println!("\nTest 8: Join Example");
140 {
141 let users = vec![
142 User { id: 1, name: "Alice".to_string() },
143 User { id: 2, name: "Bob".to_string() },
144 ];
145
146 let orders = vec![
147 Order { id: 101, user_id: 1, total: 99.99 },
148 Order { id: 102, user_id: 1, total: 149.99 },
149 ];
150
151 let user_orders = JoinQuery::new(&users, &orders).inner_join(
152 User::id_r(),
153 Order::user_id_r(),
154 |user, order| (user.name.clone(), order.total),
155 );
156
157 println!(" Joined {} user-order pairs ✅", user_orders.len());
158 }
159
160 // Example from SQL_COMPARISON - SELECT with WHERE
161 println!("\nTest 9: SQL Comparison - SELECT with WHERE");
162 {
163 #[derive(Clone, Keypaths)]
164 struct Employee {
165 department: String,
166 }
167
168 let employees = vec![
169 Employee { department: "Engineering".to_string() },
170 Employee { department: "Sales".to_string() },
171 ];
172
173 let engineering_query = Query::new(&employees)
174 .where_(Employee::department_r(), |dept| dept == "Engineering");
175 let engineering = engineering_query.all();
176
177 println!(" Found {} engineering employees ✅", engineering.len());
178 }
179
180 // Example from USAGE.md - Complex Filtering
181 println!("\nTest 10: USAGE - Complex Filtering");
182 {
183 let products = vec![
184 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
185 ];
186
187 let results_query = Query::new(&products)
188 .where_(Product::category_r(), |cat| cat == "Electronics")
189 .where_(Product::price_r(), |&price| price >= 100.0 && price <= 500.0)
190 .where_(Product::stock_r(), |&stock| stock > 10);
191 let results = results_query.order_by_float(Product::price_r());
192
193 println!(" Filtered {} products ✅", results.len());
194 }
195
196 println!("\n✅ All documentation examples compile and run successfully!");
197}110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}33fn main() {
34 let employees = create_test_data();
35
36 println!("\n╔════════════════════════════════════════════════════════════════╗");
37 println!("║ SQL Equivalence Verification Tests ║");
38 println!("╚════════════════════════════════════════════════════════════════╝\n");
39
40 // TEST 1: ORDER BY maintains exact SQL ordering (DESC)
41 println!("Test 1: ORDER BY DESC - Exact ordering");
42 println!("SQL: SELECT * FROM employees ORDER BY salary DESC;");
43
44 let ordered = Query::new(&employees).order_by_float_desc(Employee::salary_r());
45 let expected_order = vec![105000.0, 95000.0, 87000.0, 82000.0, 75000.0, 71000.0];
46 let actual_order: Vec<f64> = ordered.iter().map(|e| e.salary).collect();
47
48 let test1_pass = expected_order == actual_order;
49 print_test("ORDER BY salary DESC produces correct order", test1_pass);
50 if !test1_pass {
51 println!(" Expected: {:?}", expected_order);
52 println!(" Got: {:?}", actual_order);
53 }
54
55 // TEST 2: ORDER BY maintains exact SQL ordering (ASC)
56 println!("\nTest 2: ORDER BY ASC - Exact ordering");
57 println!("SQL: SELECT * FROM employees ORDER BY salary ASC;");
58
59 let ordered_asc = Query::new(&employees).order_by_float(Employee::salary_r());
60 let expected_asc = vec![71000.0, 75000.0, 82000.0, 87000.0, 95000.0, 105000.0];
61 let actual_asc: Vec<f64> = ordered_asc.iter().map(|e| e.salary).collect();
62
63 let test2_pass = expected_asc == actual_asc;
64 print_test("ORDER BY salary ASC produces correct order", test2_pass);
65 if !test2_pass {
66 println!(" Expected: {:?}", expected_asc);
67 println!(" Got: {:?}", actual_asc);
68 }
69
70 // TEST 3: String ordering (alphabetical)
71 println!("\nTest 3: ORDER BY name (alphabetical)");
72 println!("SQL: SELECT name FROM employees ORDER BY name;");
73
74 let ordered_names = Query::new(&employees).order_by(Employee::name_r());
75 let expected_names = vec!["Alice Cooper", "Alice Johnson", "Bob Smith", "Carol White", "David Brown", "Eve Davis"];
76 let actual_names: Vec<&str> = ordered_names.iter().map(|e| e.name.as_str()).collect();
77
78 let test3_pass = expected_names == actual_names;
79 print_test("ORDER BY name produces correct alphabetical order", test3_pass);
80 if !test3_pass {
81 println!(" Expected: {:?}", expected_names);
82 println!(" Got: {:?}", actual_names);
83 }
84
85 // TEST 4: LIKE equivalent - starts with
86 println!("\nTest 4: LIKE 'Alice%' equivalent");
87 println!("SQL: SELECT * FROM employees WHERE name LIKE 'Alice%';");
88
89 let like_alice_query = Query::new(&employees)
90 .where_(Employee::name_r(), |name| name.starts_with("Alice"));
91 let like_alice = like_alice_query.all();
92
93 let test4_pass = like_alice.len() == 2
94 && like_alice.iter().all(|e| e.name.starts_with("Alice"));
95 print_test("LIKE 'Alice%' (starts_with) works correctly", test4_pass);
96 if test4_pass {
97 for emp in &like_alice {
98 println!(" Found: {}", emp.name);
99 }
100 }
101
102 // TEST 5: LIKE equivalent - ends with
103 println!("\nTest 5: LIKE '%son' equivalent");
104 println!("SQL: SELECT * FROM employees WHERE name LIKE '%son';");
105
106 let like_son_query = Query::new(&employees)
107 .where_(Employee::name_r(), |name| name.ends_with("son"));
108 let like_son = like_son_query.all();
109
110 let test5_pass = like_son.len() == 1 && like_son[0].name == "Alice Johnson";
111 print_test("LIKE '%son' (ends_with) works correctly", test5_pass);
112 if test5_pass {
113 for emp in &like_son {
114 println!(" Found: {}", emp.name);
115 }
116 }
117
118 // TEST 6: LIKE equivalent - contains
119 println!("\nTest 6: LIKE '%mit%' equivalent");
120 println!("SQL: SELECT * FROM employees WHERE name LIKE '%mit%';");
121
122 let like_mit_query = Query::new(&employees)
123 .where_(Employee::name_r(), |name| name.contains("mit"));
124 let like_mit = like_mit_query.all();
125
126 let test6_pass = like_mit.len() == 1 && like_mit[0].name == "Bob Smith";
127 print_test("LIKE '%mit%' (contains) works correctly", test6_pass);
128 if test6_pass {
129 for emp in &like_mit {
130 println!(" Found: {}", emp.name);
131 }
132 }
133
134 // TEST 7: IN clause equivalent
135 println!("\nTest 7: IN clause equivalent");
136 println!("SQL: SELECT * FROM employees WHERE department IN ('Engineering', 'Sales');");
137
138 let in_depts_query = Query::new(&employees)
139 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales");
140 let in_depts = in_depts_query.all();
141
142 let test7_pass = in_depts.len() == 5 // 3 Engineering + 2 Sales
143 && in_depts.iter().all(|e| e.department == "Engineering" || e.department == "Sales");
144 print_test("IN clause works correctly", test7_pass);
145 println!(" Found {} employees in Engineering or Sales", in_depts.len());
146
147 // TEST 8: BETWEEN equivalent
148 println!("\nTest 8: BETWEEN clause equivalent");
149 println!("SQL: SELECT * FROM employees WHERE salary BETWEEN 75000 AND 90000;");
150
151 let between_query = Query::new(&employees)
152 .where_(Employee::salary_r(), |&sal| sal >= 75000.0 && sal <= 90000.0);
153 let between = between_query.all();
154
155 let test8_pass = between.len() == 3;
156 print_test("BETWEEN clause works correctly", test8_pass);
157 println!(" Found {} employees with salary between 75K-90K", between.len());
158
159 // TEST 9: COUNT with WHERE
160 println!("\nTest 9: COUNT with WHERE");
161 println!("SQL: SELECT COUNT(*) FROM employees WHERE department = 'Engineering';");
162
163 let count_eng = Query::new(&employees)
164 .where_(Employee::department_r(), |dept| dept == "Engineering")
165 .count();
166
167 let test9_pass = count_eng == 3;
168 print_test("COUNT with WHERE produces correct result", test9_pass);
169 println!(" Count: {} (expected 3)", count_eng);
170
171 // TEST 10: AVG produces exact result
172 println!("\nTest 10: AVG aggregation accuracy");
173 println!("SQL: SELECT AVG(salary) FROM employees WHERE department = 'Engineering';");
174
175 let avg_sal = Query::new(&employees)
176 .where_(Employee::department_r(), |dept| dept == "Engineering")
177 .avg(Employee::salary_r())
178 .unwrap_or(0.0);
179
180 let expected_avg = (95000.0 + 87000.0 + 105000.0) / 3.0;
181 let test10_pass = (avg_sal - expected_avg).abs() < 0.01;
182 print_test("AVG produces mathematically correct result", test10_pass);
183 println!(" Average: ${:.2} (expected ${:.2})", avg_sal, expected_avg);
184
185 // TEST 11: MIN and MAX
186 println!("\nTest 11: MIN and MAX aggregations");
187 println!("SQL: SELECT MIN(salary), MAX(salary) FROM employees;");
188
189 let min_sal = Query::new(&employees).min_float(Employee::salary_r()).unwrap_or(0.0);
190 let max_sal = Query::new(&employees).max_float(Employee::salary_r()).unwrap_or(0.0);
191
192 let test11_pass = min_sal == 71000.0 && max_sal == 105000.0;
193 print_test("MIN and MAX produce correct results", test11_pass);
194 println!(" MIN: ${:.2}, MAX: ${:.2}", min_sal, max_sal);
195
196 // TEST 12: Complex WHERE with AND/OR
197 println!("\nTest 12: Complex WHERE (AND + OR)");
198 println!("SQL: SELECT * FROM employees WHERE (department = 'Engineering' OR department = 'Sales') AND salary > 80000;");
199
200 let complex_query = Query::new(&employees)
201 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
202 .where_(Employee::salary_r(), |&sal| sal > 80000.0);
203 let complex = complex_query.all();
204
205 let test12_pass = complex.len() == 4; // Alice J ($95k), Bob ($87k), David ($82k), Alice C ($105k)
206 print_test("Complex WHERE clause works correctly", test12_pass);
207 println!(" Found {} employees", complex.len());
208
209 // TEST 13: Case-sensitive string comparison (SQL default)
210 println!("\nTest 13: Case-sensitive comparison (like SQL)");
211 println!("SQL: SELECT * FROM employees WHERE department = 'engineering'; -- should find 0");
212
213 let case_sensitive = Query::new(&employees)
214 .where_(Employee::department_r(), |dept| dept == "engineering") // lowercase
215 .count();
216
217 let test13_pass = case_sensitive == 0;
218 print_test("Case-sensitive comparison (SQL default)", test13_pass);
219 println!(" Found {} with lowercase 'engineering' (expected 0)", case_sensitive);
220
221 // TEST 14: Case-insensitive LIKE equivalent
222 println!("\nTest 14: Case-insensitive LIKE (ILIKE equivalent)");
223 println!("SQL: SELECT * FROM employees WHERE LOWER(name) LIKE '%alice%';");
224
225 let ilike_query = Query::new(&employees)
226 .where_(Employee::name_r(), |name| name.to_lowercase().contains("alice"));
227 let ilike = ilike_query.all();
228
229 let test14_pass = ilike.len() == 2;
230 print_test("Case-insensitive LIKE works correctly", test14_pass);
231 println!(" Found {} employees with 'alice' (case-insensitive)", ilike.len());
232
233 // TEST 15: LIMIT produces exact subset
234 println!("\nTest 15: LIMIT clause");
235 println!("SQL: SELECT * FROM employees ORDER BY salary DESC LIMIT 3;");
236
237 let limited = Query::new(&employees)
238 .order_by_float_desc(Employee::salary_r())
239 .into_iter()
240 .take(3)
241 .collect::<Vec<_>>();
242
243 let test15_pass = limited.len() == 3
244 && limited[0].salary == 105000.0
245 && limited[1].salary == 95000.0
246 && limited[2].salary == 87000.0;
247 print_test("LIMIT returns correct top-N results", test15_pass);
248 println!(" Top 3 salaries: ${:.0}, ${:.0}, ${:.0}",
249 limited[0].salary, limited[1].salary, limited[2].salary);
250
251 // TEST 16: GROUP BY produces correct groups
252 println!("\nTest 16: GROUP BY");
253 println!("SQL: SELECT department, COUNT(*) FROM employees GROUP BY department;");
254
255 let grouped = Query::new(&employees).group_by(Employee::department_r());
256 let eng_count = grouped.get("Engineering").map(|v| v.len()).unwrap_or(0);
257 let sales_count = grouped.get("Sales").map(|v| v.len()).unwrap_or(0);
258 let marketing_count = grouped.get("Marketing").map(|v| v.len()).unwrap_or(0);
259
260 let test16_pass = eng_count == 3 && sales_count == 2 && marketing_count == 1;
261 print_test("GROUP BY produces correct counts", test16_pass);
262 println!(" Engineering: {}, Sales: {}, Marketing: {}", eng_count, sales_count, marketing_count);
263
264 // TEST 17: Email pattern matching (regex-like)
265 println!("\nTest 17: Email domain filtering (LIKE '%@example.com')");
266 println!("SQL: SELECT * FROM employees WHERE email LIKE '%@example.com';");
267
268 let example_emails = Query::new(&employees)
269 .where_(Employee::email_r(), |email| email.ends_with("@example.com"))
270 .count();
271
272 let test17_pass = example_emails == 6; // All employees have @example.com emails
273 print_test("Email pattern matching works correctly", test17_pass);
274 println!(" Found {} employees with @example.com emails", example_emails);
275
276 // Summary
277 println!("\n╔════════════════════════════════════════════════════════════════╗");
278 println!("║ Test Summary ║");
279 println!("╚════════════════════════════════════════════════════════════════╝\n");
280
281 let tests = vec![
282 ("ORDER BY DESC", test1_pass),
283 ("ORDER BY ASC", test2_pass),
284 ("ORDER BY name", test3_pass),
285 ("LIKE 'prefix%'", test4_pass),
286 ("LIKE '%suffix'", test5_pass),
287 ("LIKE '%contains%'", test6_pass),
288 ("IN clause", test7_pass),
289 ("BETWEEN clause", test8_pass),
290 ("COUNT", test9_pass),
291 ("AVG accuracy", test10_pass),
292 ("MIN/MAX", test11_pass),
293 ("Complex WHERE", test12_pass),
294 ("Case-sensitive", test13_pass),
295 ("Case-insensitive", test14_pass),
296 ("LIMIT", test15_pass),
297 ("GROUP BY", test16_pass),
298 ("Email patterns", test17_pass),
299 ];
300
301 let passed = tests.iter().filter(|(_, p)| *p).count();
302 let total = tests.len();
303
304 println!("Results: {}/{} tests passed", passed, total);
305
306 if passed == total {
307 println!("\n🎉 All tests PASSED! Rust Query Builder produces exact SQL-equivalent results!");
308 println!("\n✅ Verified:");
309 println!(" • Exact ordering (ASC/DESC)");
310 println!(" • LIKE operations (starts_with, ends_with, contains)");
311 println!(" • IN clause (OR conditions)");
312 println!(" • BETWEEN clause");
313 println!(" • Aggregations (COUNT, AVG, MIN, MAX)");
314 println!(" • Complex WHERE conditions");
315 println!(" • Case sensitivity");
316 println!(" • LIMIT clause");
317 println!(" • GROUP BY");
318 println!(" • Pattern matching");
319 } else {
320 println!("\n⚠️ {} test(s) failed. See details above.", total - passed);
321 }
322}230fn main() {
231 println!("\n╔════════════════════════════════════════════════════════════════╗");
232 println!("║ Custom Queryable Implementation Demo ║");
233 println!("╚════════════════════════════════════════════════════════════════╝\n");
234
235 // ============================================================================
236 // DEMO 1: PaginatedCollection
237 // ============================================================================
238 println!("═══════════════════════════════════════════════════════════════");
239 println!("Demo 1: PaginatedCollection (custom container)");
240 println!("═══════════════════════════════════════════════════════════════\n");
241
242 let mut paginated = PaginatedCollection::new(3); // 3 items per page
243
244 paginated.add(create_sample_product(1, "Laptop", 999.0, "Electronics", true));
245 paginated.add(create_sample_product(2, "Mouse", 29.0, "Electronics", true));
246 paginated.add(create_sample_product(3, "Keyboard", 129.0, "Electronics", true));
247 paginated.add(create_sample_product(4, "Desk", 299.0, "Furniture", true));
248 paginated.add(create_sample_product(5, "Chair", 199.0, "Furniture", false));
249
250 println!(" Created paginated collection:");
251 println!(" Total items: {}", paginated.total_items());
252 println!(" Pages: {}", paginated.pages.len());
253
254 // Now we can query it using the Queryable trait!
255 // Collect to owned Vec for querying
256 let items: Vec<Product> = paginated.query_iter().cloned().collect();
257 let query = Query::new(&items)
258 .where_(Product::category_r(), |cat| cat == "Electronics");
259 let electronics = query.all();
260
261 println!("\n Querying paginated collection:");
262 println!(" Electronics found: {}", electronics.len());
263 for product in electronics {
264 println!(" • {}: ${:.2}", product.name, product.price);
265 }
266
267 // ============================================================================
268 // DEMO 2: CircularBuffer
269 // ============================================================================
270 println!("\n═══════════════════════════════════════════════════════════════");
271 println!("Demo 2: CircularBuffer (fixed capacity)");
272 println!("═══════════════════════════════════════════════════════════════\n");
273
274 let mut circular = CircularBuffer::new(3); // Capacity: 3
275
276 circular.push(create_sample_product(1, "Product 1", 100.0, "A", true));
277 circular.push(create_sample_product(2, "Product 2", 200.0, "B", true));
278 circular.push(create_sample_product(3, "Product 3", 300.0, "C", true));
279 circular.push(create_sample_product(4, "Product 4", 400.0, "D", true)); // Pushes out Product 1
280
281 println!(" Circular buffer (capacity 3, added 4 items):");
282 println!(" Current size: {}", circular.len());
283
284 // Query the circular buffer
285 let circ_items: Vec<Product> = circular.query_iter().cloned().collect();
286 let circ_query = Query::new(&circ_items);
287 let avg_price = circ_query.avg(Product::price_r()).unwrap_or(0.0);
288
289 println!("\n Querying circular buffer:");
290 println!(" Average price: ${:.2}", avg_price);
291 println!(" Items:");
292 for (i, product) in circ_items.iter().enumerate() {
293 println!(" {}. {}: ${:.2}", i + 1, product.name, product.price);
294 }
295
296 // ============================================================================
297 // DEMO 3: FilteredStorage
298 // ============================================================================
299 println!("\n═══════════════════════════════════════════════════════════════");
300 println!("Demo 3: FilteredStorage (auto-filtering container)");
301 println!("═══════════════════════════════════════════════════════════════\n");
302
303 let mut filtered = FilteredStorage::new(|p: &Product| p.price < 200.0);
304
305 println!(" FilteredStorage (only accepts items < $200):");
306 println!(" Adding Laptop ($999): {}", filtered.add(create_sample_product(1, "Laptop", 999.0, "Electronics", true)));
307 println!(" Adding Mouse ($29): {}", filtered.add(create_sample_product(2, "Mouse", 29.0, "Electronics", true)));
308 println!(" Adding Keyboard ($129): {}", filtered.add(create_sample_product(3, "Keyboard", 129.0, "Electronics", true)));
309 println!(" Total stored: {}", filtered.len());
310
311 // Query the filtered storage
312 let filt_items: Vec<Product> = filtered.query_iter().cloned().collect();
313 let filt_query = Query::new(&filt_items)
314 .where_(Product::in_stock_r(), |&v| v);
315 let in_stock = filt_query.all();
316
317 println!("\n Querying filtered storage:");
318 println!(" In stock items: {}", in_stock.len());
319
320 // ============================================================================
321 // DEMO 4: CategoryIndex
322 // ============================================================================
323 println!("\n═══════════════════════════════════════════════════════════════");
324 println!("Demo 4: CategoryIndex (indexed by category)");
325 println!("═══════════════════════════════════════════════════════════════\n");
326
327 let mut category_index = CategoryIndex::new();
328
329 category_index.add("Electronics".to_string(), create_sample_product(1, "Monitor", 349.0, "Electronics", true));
330 category_index.add("Electronics".to_string(), create_sample_product(2, "Webcam", 79.0, "Electronics", true));
331 category_index.add("Furniture".to_string(), create_sample_product(3, "Desk", 299.0, "Furniture", true));
332 category_index.add("Furniture".to_string(), create_sample_product(4, "Lamp", 39.0, "Furniture", true));
333
334 println!(" CategoryIndex:");
335 println!(" Categories: {:?}", category_index.categories());
336 println!(" Total items: {}", category_index.total_items());
337
338 // Query across all categories
339 let idx_items: Vec<Product> = category_index.query_iter().cloned().collect();
340 let idx_query = Query::new(&idx_items);
341 let expensive = idx_query
342 .where_(Product::price_r(), |&p| p > 100.0);
343 let expensive_items = expensive.all();
344
345 println!("\n Querying category index:");
346 println!(" Expensive items (>$100): {}", expensive_items.len());
347 for product in expensive_items {
348 println!(" • {}: ${:.2} ({})", product.name, product.price, product.category);
349 }
350
351 // ============================================================================
352 // DEMO 5: LazyLoader
353 // ============================================================================
354 println!("\n═══════════════════════════════════════════════════════════════");
355 println!("Demo 5: LazyLoader (simulated lazy loading)");
356 println!("═══════════════════════════════════════════════════════════════\n");
357
358 let loader = LazyLoader::new(vec![
359 create_sample_product(1, "Item 1", 50.0, "A", true),
360 create_sample_product(2, "Item 2", 150.0, "B", true),
361 create_sample_product(3, "Item 3", 250.0, "C", true),
362 ]);
363
364 println!(" LazyLoader:");
365 println!(" Total available: {}", loader.total_count());
366 println!(" Currently loaded: {}", loader.loaded_count());
367
368 // Query loaded items
369 let loader_items: Vec<Product> = loader.query_iter().cloned().collect();
370 let loader_query = Query::new(&loader_items);
371 let total_value = loader_query.sum(Product::price_r());
372
373 println!("\n Querying lazy loader:");
374 println!(" Total value: ${:.2}", total_value);
375
376 // ============================================================================
377 // DEMO 6: Custom Container with LazyQuery
378 // ============================================================================
379 println!("\n═══════════════════════════════════════════════════════════════");
380 println!("Demo 6: Using LazyQuery with custom containers");
381 println!("═══════════════════════════════════════════════════════════════\n");
382
383 let mut circular = CircularBuffer::new(5);
384 for i in 1..=10 {
385 circular.push(create_sample_product(
386 i,
387 &format!("Product {}", i),
388 i as f64 * 50.0,
389 if i % 2 == 0 { "Even" } else { "Odd" },
390 true,
391 ));
392 }
393
394 println!(" Circular buffer (capacity 5, added 10 items):");
395 println!(" Current size: {}", circular.len());
396
397 // Use LazyQuery for early termination!
398 let circ_vec: Vec<Product> = circular.query_iter().cloned().collect();
399 let first_expensive = LazyQuery::new(&circ_vec)
400 .where_(Product::price_r(), |&p| p > 300.0)
401 .first();
402
403 if let Some(product) = first_expensive {
404 println!("\n First expensive item (lazy query):");
405 println!(" {}: ${:.2}", product.name, product.price);
406 }
407
408 // ============================================================================
409 // DEMO 7: Implementing Queryable for Wrapper Types
410 // ============================================================================
411 println!("\n═══════════════════════════════════════════════════════════════");
412 println!("Demo 7: Queryable for wrapper types");
413 println!("═══════════════════════════════════════════════════════════════\n");
414
415 /// A simple wrapper around Vec with metadata
416 struct VersionedCollection<T> {
417 items: Vec<T>,
418 version: u32,
419 last_modified: String,
420 }
421
422 impl<T> Queryable<T> for VersionedCollection<T> {
423 fn query_iter(&self) -> Box<dyn Iterator<Item = &T> + '_> {
424 Box::new(self.items.iter())
425 }
426 }
427
428 let versioned = VersionedCollection {
429 items: vec![
430 create_sample_product(1, "V1 Product", 99.0, "Test", true),
431 create_sample_product(2, "V2 Product", 199.0, "Test", true),
432 ],
433 version: 2,
434 last_modified: "2025-10-11".to_string(),
435 };
436
437 println!(" VersionedCollection:");
438 println!(" Version: {}", versioned.version);
439 println!(" Last modified: {}", versioned.last_modified);
440
441 let versioned_items: Vec<Product> = versioned.query_iter().cloned().collect();
442 let query = Query::new(&versioned_items);
443 println!(" Items: {}", query.count());
444
445 // ============================================================================
446 // DEMO 8: Real-World Example - Cache with TTL
447 // ============================================================================
448 println!("\n═══════════════════════════════════════════════════════════════");
449 println!("Demo 8: Cache container (real-world example)");
450 println!("═══════════════════════════════════════════════════════════════\n");
451
452 use std::time::{Duration, SystemTime};
453
454 struct CachedItem<T> {
455 item: T,
456 inserted_at: SystemTime,
457 ttl: Duration,
458 }
459
460 struct Cache<T> {
461 items: Vec<CachedItem<T>>,
462 }
463
464 impl<T> Cache<T> {
465 fn new() -> Self {
466 Self { items: Vec::new() }
467 }
468
469 fn insert(&mut self, item: T, ttl: Duration) {
470 self.items.push(CachedItem {
471 item,
472 inserted_at: SystemTime::now(),
473 ttl,
474 });
475 }
476
477 fn valid_items(&self) -> Vec<&T> {
478 let now = SystemTime::now();
479 self.items
480 .iter()
481 .filter(|cached| {
482 now.duration_since(cached.inserted_at)
483 .map_or(false, |elapsed| elapsed < cached.ttl)
484 })
485 .map(|cached| &cached.item)
486 .collect()
487 }
488 }
489
490 // Implement Queryable to query only valid (non-expired) items
491 impl<T> Queryable<T> for Cache<T> {
492 fn query_iter(&self) -> Box<dyn Iterator<Item = &T> + '_> {
493 let now = SystemTime::now();
494 Box::new(
495 self.items
496 .iter()
497 .filter(move |cached| {
498 now.duration_since(cached.inserted_at)
499 .map_or(false, |elapsed| elapsed < cached.ttl)
500 })
501 .map(|cached| &cached.item),
502 )
503 }
504 }
505
506 let mut cache = Cache::new();
507 cache.insert(create_sample_product(1, "Cached Item 1", 100.0, "A", true), Duration::from_secs(60));
508 cache.insert(create_sample_product(2, "Cached Item 2", 200.0, "B", true), Duration::from_secs(60));
509
510 let valid = cache.valid_items();
511 println!(" Cache:");
512 println!(" Total items: {}", cache.items.len());
513 println!(" Valid items: {}", valid.len());
514
515 // Query the cache
516 let cache_items: Vec<Product> = cache.query_iter().cloned().collect();
517 let cache_query = Query::new(&cache_items);
518 println!(" Queryable items: {}", cache_query.count());
519
520 // ============================================================================
521 // Summary
522 // ============================================================================
523 println!("\n╔════════════════════════════════════════════════════════════════╗");
524 println!("║ Summary: Implementing Queryable ║");
525 println!("╚════════════════════════════════════════════════════════════════╝\n");
526
527 println!("✅ How to make any container queryable:\n");
528 println!(" 1. Implement the Queryable<T> trait:");
529 println!(" ```rust");
530 println!(" impl<T> Queryable<T> for MyContainer<T> {{");
531 println!(" fn query_iter(&self) -> Box<dyn Iterator<Item = &T> + '_> {{");
532 println!(" Box::new(self.items.iter())");
533 println!(" }}");
534 println!(" }}");
535 println!(" ```\n");
536
537 println!(" 2. Convert to Vec or slice for querying:");
538 println!(" ```rust");
539 println!(" let items: Vec<&Product> = container.query_iter().collect();");
540 println!(" let query = Query::new(&items);");
541 println!(" ```\n");
542
543 println!(" 3. Now use all query operations:");
544 println!(" ```rust");
545 println!(" let results = query.where_(...).all();");
546 println!(" let count = query.count();");
547 println!(" let total = query.sum(field);");
548 println!(" ```\n");
549
550 println!("📝 Custom containers demonstrated:");
551 println!(" • PaginatedCollection - Items stored in pages");
552 println!(" • CircularBuffer - Fixed-capacity FIFO buffer");
553 println!(" • FilteredStorage - Auto-filtering container");
554 println!(" • CategoryIndex - Indexed by category");
555 println!(" • LazyLoader - Simulated lazy loading");
556 println!(" • VersionedCollection - Wrapper with metadata");
557 println!(" • Cache - TTL-based cache\n");
558
559 println!("💡 Use cases:");
560 println!(" • Database result wrappers");
561 println!(" • Custom data structures");
562 println!(" • Specialized collections");
563 println!(" • Caches and buffers");
564 println!(" • Event streams");
565 println!(" • Any container that holds items!\n");
566
567 println!("✓ Custom Queryable demo complete!\n");
568}84fn main() {
85 let employees = create_employees();
86 let departments = create_departments();
87 let projects = create_projects();
88
89 println!("\n╔════════════════════════════════════════════════════════════════════════╗");
90 println!("║ SQL vs Rust Query Builder Comparison ║");
91 println!("║ Demonstrating equivalent operations ║");
92 println!("╚════════════════════════════════════════════════════════════════════════╝");
93
94 // ============================================================================
95 // EXAMPLE 1: Simple SELECT with WHERE
96 // ============================================================================
97 print_separator("Example 1: SELECT with WHERE clause");
98 print_query(
99 "SELECT * FROM employees WHERE department = 'Engineering';",
100 "Filter employees by department"
101 );
102
103 let eng_query = Query::new(&employees)
104 .where_(Employee::department_r(), |dept| dept == "Engineering");
105 let engineering_employees = eng_query.all();
106
107 for emp in &engineering_employees {
108 println!(" ID: {}, Name: {}, Salary: ${:.2}", emp.id, emp.name, emp.salary);
109 }
110 println!("\nRust Query Builder:");
111 println!("Query::new(&employees)");
112 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\")");
113 println!(" .all()");
114 println!("✓ Found {} employees", engineering_employees.len());
115
116 // ============================================================================
117 // EXAMPLE 2: SELECT specific columns
118 // ============================================================================
119 print_separator("Example 2: SELECT specific columns (Projection)");
120 print_query(
121 "SELECT name FROM employees WHERE salary > 80000;",
122 "Get names of high-earning employees"
123 );
124
125 let high_earners = Query::new(&employees)
126 .where_(Employee::salary_r(), |&salary| salary > 80000.0)
127 .select(Employee::name_r());
128
129 for name in &high_earners {
130 println!(" {}", name);
131 }
132 println!("\nRust Query Builder:");
133 println!("Query::new(&employees)");
134 println!(" .where_(Employee::salary_r(), |&salary| salary > 80000.0)");
135 println!(" .select(Employee::name_r())");
136 println!("✓ Found {} employees", high_earners.len());
137
138 // ============================================================================
139 // EXAMPLE 3: COUNT
140 // ============================================================================
141 print_separator("Example 3: COUNT aggregation");
142 print_query(
143 "SELECT COUNT(*) FROM employees WHERE age < 30;",
144 "Count young employees"
145 );
146
147 let young_count = Query::new(&employees)
148 .where_(Employee::age_r(), |&age| age < 30)
149 .count();
150
151 println!(" Count: {}", young_count);
152 println!("\nRust Query Builder:");
153 println!("Query::new(&employees)");
154 println!(" .where_(Employee::age_r(), |&age| age < 30)");
155 println!(" .count()");
156 println!("✓ Result: {}", young_count);
157
158 // ============================================================================
159 // EXAMPLE 4: SUM, AVG, MIN, MAX
160 // ============================================================================
161 print_separator("Example 4: Aggregate functions (SUM, AVG, MIN, MAX)");
162 print_query(
163 "SELECT \n\
164 SUM(salary) as total_salary,\n\
165 AVG(salary) as avg_salary,\n\
166 MIN(salary) as min_salary,\n\
167 MAX(salary) as max_salary\n\
168 FROM employees WHERE department = 'Engineering';",
169 "Engineering department salary statistics"
170 );
171
172 let eng_query = Query::new(&employees)
173 .where_(Employee::department_r(), |dept| dept == "Engineering");
174
175 let total = eng_query.sum(Employee::salary_r());
176 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
177 let min = eng_query.min_float(Employee::salary_r()).unwrap_or(0.0);
178 let max = eng_query.max_float(Employee::salary_r()).unwrap_or(0.0);
179
180 println!(" Total Salary: ${:.2}", total);
181 println!(" Avg Salary: ${:.2}", avg);
182 println!(" Min Salary: ${:.2}", min);
183 println!(" Max Salary: ${:.2}", max);
184
185 println!("\nRust Query Builder:");
186 println!("let query = Query::new(&employees)");
187 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\");");
188 println!("query.sum(Employee::salary_r()) // ${:.2}", total);
189 println!("query.avg(Employee::salary_r()) // ${:.2}", avg);
190 println!("query.min_float(Employee::salary_r()) // ${:.2}", min);
191 println!("query.max_float(Employee::salary_r()) // ${:.2}", max);
192
193 // ============================================================================
194 // EXAMPLE 5: GROUP BY with aggregation
195 // ============================================================================
196 print_separator("Example 5: GROUP BY with aggregation");
197 print_query(
198 "SELECT \n\
199 department,\n\
200 COUNT(*) as emp_count,\n\
201 AVG(salary) as avg_salary\n\
202 FROM employees\n\
203 GROUP BY department;",
204 "Statistics by department"
205 );
206
207 let by_dept = Query::new(&employees).group_by(Employee::department_r());
208
209 for (dept, emps) in &by_dept {
210 let dept_query = Query::new(emps);
211 let count = emps.len();
212 let avg_sal = dept_query.avg(Employee::salary_r()).unwrap_or(0.0);
213 println!(" {}: {} employees, avg salary ${:.2}", dept, count, avg_sal);
214 }
215
216 println!("\nRust Query Builder:");
217 println!("let by_dept = Query::new(&employees).group_by(Employee::department_r());");
218 println!("for (dept, emps) in &by_dept {{");
219 println!(" let dept_query = Query::new(emps);");
220 println!(" dept_query.avg(Employee::salary_r())");
221 println!("}}");
222
223 // ============================================================================
224 // EXAMPLE 6: ORDER BY
225 // ============================================================================
226 print_separator("Example 6: ORDER BY");
227 print_query(
228 "SELECT name, salary FROM employees\n\
229 WHERE department = 'Sales'\n\
230 ORDER BY salary DESC;",
231 "Sales employees ordered by salary (descending)"
232 );
233
234 let sales_sorted = Query::new(&employees)
235 .where_(Employee::department_r(), |dept| dept == "Sales")
236 .order_by_float_desc(Employee::salary_r());
237
238 for emp in &sales_sorted {
239 println!(" {}: ${:.2}", emp.name, emp.salary);
240 }
241
242 println!("\nRust Query Builder:");
243 println!("Query::new(&employees)");
244 println!(" .where_(Employee::department_r(), |dept| dept == \"Sales\")");
245 println!(" .order_by_float_desc(Employee::salary_r())");
246
247 // ============================================================================
248 // EXAMPLE 7: Multiple WHERE conditions (AND)
249 // ============================================================================
250 print_separator("Example 7: Multiple WHERE conditions (AND)");
251 print_query(
252 "SELECT * FROM employees\n\
253 WHERE salary > 70000 AND age < 35;",
254 "High-earning young employees"
255 );
256
257 let filter_query = Query::new(&employees)
258 .where_(Employee::salary_r(), |&salary| salary > 70000.0)
259 .where_(Employee::age_r(), |&age| age < 35);
260 let filtered = filter_query.all();
261
262 for emp in &filtered {
263 println!(" {}: Age {}, Salary ${:.2}", emp.name, emp.age, emp.salary);
264 }
265
266 println!("\nRust Query Builder:");
267 println!("Query::new(&employees)");
268 println!(" .where_(Employee::salary_r(), |&salary| salary > 70000.0)");
269 println!(" .where_(Employee::age_r(), |&age| age < 35)");
270 println!(" .all()");
271 println!("✓ Found {} employees", filtered.len());
272
273 // ============================================================================
274 // EXAMPLE 8: LIMIT (TOP N)
275 // ============================================================================
276 print_separator("Example 8: LIMIT / TOP N");
277 print_query(
278 "SELECT TOP 3 name, salary FROM employees\n\
279 ORDER BY salary DESC;",
280 "Top 3 highest paid employees"
281 );
282
283 let top_earners = Query::new(&employees)
284 .order_by_float_desc(Employee::salary_r());
285
286 for (i, emp) in top_earners.iter().take(3).enumerate() {
287 println!(" {}. {}: ${:.2}", i + 1, emp.name, emp.salary);
288 }
289
290 println!("\nRust Query Builder:");
291 println!("Query::new(&employees)");
292 println!(" .order_by_float_desc(Employee::salary_r())");
293 println!(" .into_iter().take(3)");
294
295 // ============================================================================
296 // EXAMPLE 9: OFFSET and LIMIT (Pagination)
297 // ============================================================================
298 print_separator("Example 9: OFFSET and LIMIT (Pagination)");
299 print_query(
300 "SELECT name FROM employees\n\
301 ORDER BY name\n\
302 LIMIT 3 OFFSET 3;",
303 "Page 2 of employee names (3 per page)"
304 );
305
306 let page_2 = Query::new(&employees)
307 .order_by(Employee::name_r())
308 .into_iter()
309 .skip(3)
310 .take(3)
311 .collect::<Vec<_>>();
312
313 for emp in &page_2 {
314 println!(" {}", emp.name);
315 }
316
317 println!("\nRust Query Builder:");
318 println!("Query::new(&employees)");
319 println!(" .order_by(Employee::name_r())");
320 println!(" .into_iter().skip(3).take(3)");
321
322 // ============================================================================
323 // EXAMPLE 10: INNER JOIN
324 // ============================================================================
325 print_separator("Example 10: INNER JOIN");
326 print_query(
327 "SELECT e.name, d.name as dept_name, d.budget\n\
328 FROM employees e\n\
329 INNER JOIN departments d ON e.department = d.name;",
330 "Employees with their department info"
331 );
332
333 let emp_dept = JoinQuery::new(&employees, &departments).inner_join(
334 Employee::department_r(),
335 Department::name_r(),
336 |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget),
337 );
338
339 for (emp_name, dept_name, budget) in emp_dept.iter().take(5) {
340 println!(" {} works in {} (Budget: ${:.0})", emp_name, dept_name, budget);
341 }
342 println!(" ... (showing first 5)");
343
344 println!("\nRust Query Builder:");
345 println!("JoinQuery::new(&employees, &departments).inner_join(");
346 println!(" Employee::department_r(),");
347 println!(" Department::name_r(),");
348 println!(" |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget)");
349 println!(")");
350 println!("✓ Found {} matches", emp_dept.len());
351
352 // ============================================================================
353 // EXAMPLE 11: GROUP BY with HAVING equivalent
354 // ============================================================================
355 print_separator("Example 11: GROUP BY with filtering (HAVING equivalent)");
356 print_query(
357 "SELECT city, COUNT(*) as emp_count, AVG(salary) as avg_salary\n\
358 FROM employees\n\
359 GROUP BY city\n\
360 HAVING COUNT(*) > 1;",
361 "Cities with multiple employees"
362 );
363
364 let by_city = Query::new(&employees).group_by(Employee::city_r());
365 let mut city_stats: Vec<_> = by_city
366 .iter()
367 .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent
368 .map(|(city, emps)| {
369 let avg_sal = Query::new(emps).avg(Employee::salary_r()).unwrap_or(0.0);
370 (city.clone(), emps.len(), avg_sal)
371 })
372 .collect();
373
374 city_stats.sort_by(|a, b| b.1.cmp(&a.1)); // Sort by count
375
376 for (city, count, avg_sal) in &city_stats {
377 println!(" {}: {} employees, avg salary ${:.2}", city, count, avg_sal);
378 }
379
380 println!("\nRust Query Builder:");
381 println!("let by_city = Query::new(&employees).group_by(Employee::city_r());");
382 println!("by_city.iter()");
383 println!(" .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent");
384 println!(" .map(|(city, emps)| {{");
385 println!(" let avg = Query::new(emps).avg(Employee::salary_r());");
386 println!(" (city, emps.len(), avg)");
387 println!(" }})");
388
389 // ============================================================================
390 // EXAMPLE 12: Complex query with multiple operations
391 // ============================================================================
392 print_separator("Example 12: Complex multi-operation query");
393 print_query(
394 "SELECT name, salary, age\n\
395 FROM employees\n\
396 WHERE department IN ('Engineering', 'Sales')\n\
397 AND salary BETWEEN 80000 AND 100000\n\
398 AND age >= 30\n\
399 ORDER BY salary DESC;",
400 "Experienced mid-to-senior level employees in core departments"
401 );
402
403 let complex_query = Query::new(&employees)
404 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
405 .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)
406 .where_(Employee::age_r(), |&age| age >= 30)
407 .order_by_float_desc(Employee::salary_r());
408
409 for emp in &complex_query {
410 println!(" {}: Age {}, {} dept, ${:.2}", emp.name, emp.age, emp.department, emp.salary);
411 }
412
413 println!("\nRust Query Builder:");
414 println!("Query::new(&employees)");
415 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\" || dept == \"Sales\")");
416 println!(" .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)");
417 println!(" .where_(Employee::age_r(), |&age| age >= 30)");
418 println!(" .order_by_float_desc(Employee::salary_r())");
419 println!("✓ Found {} employees", complex_query.len());
420
421 // ============================================================================
422 // EXAMPLE 13: Three-table JOIN
423 // ============================================================================
424 print_separator("Example 13: Three-table JOIN");
425 print_query(
426 "SELECT p.name as project, d.name as department, d.location\n\
427 FROM projects p\n\
428 INNER JOIN departments d ON p.department_id = d.id;",
429 "Projects with their department details"
430 );
431
432 let proj_dept = JoinQuery::new(&projects, &departments).inner_join(
433 Project::department_id_r(),
434 Department::id_r(),
435 |proj, dept| {
436 (proj.name.clone(), dept.name.clone(), dept.location.clone(), proj.budget)
437 },
438 );
439
440 for (proj_name, dept_name, location, budget) in &proj_dept {
441 println!(" {}: {} dept in {} (${:.0})", proj_name, dept_name, location, budget);
442 }
443
444 println!("\nRust Query Builder:");
445 println!("JoinQuery::new(&projects, &departments).inner_join(");
446 println!(" Project::department_id_r(),");
447 println!(" Department::id_r(),");
448 println!(" |proj, dept| (proj.name, dept.name, dept.location, proj.budget)");
449 println!(")");
450
451 // ============================================================================
452 // EXAMPLE 14: Subquery equivalent (using intermediate results)
453 // ============================================================================
454 print_separator("Example 14: Subquery equivalent");
455 print_query(
456 "SELECT * FROM employees\n\
457 WHERE salary > (SELECT AVG(salary) FROM employees);",
458 "Employees earning above average"
459 );
460
461 let avg_salary = Query::new(&employees)
462 .avg(Employee::salary_r())
463 .unwrap_or(0.0);
464
465 let above_avg_query = Query::new(&employees)
466 .where_(Employee::salary_r(), move |&sal| sal > avg_salary);
467 let above_avg = above_avg_query.all();
468
469 println!(" Average salary: ${:.2}", avg_salary);
470 for emp in &above_avg {
471 println!(" {}: ${:.2} ({:.1}% above average)",
472 emp.name, emp.salary, ((emp.salary - avg_salary) / avg_salary * 100.0));
473 }
474
475 println!("\nRust Query Builder:");
476 println!("let avg = Query::new(&employees).avg(Employee::salary_r()).unwrap_or(0.0);");
477 println!("Query::new(&employees)");
478 println!(" .where_(Employee::salary_r(), |&sal| sal > avg)");
479 println!(" .all()");
480 println!("✓ Found {} employees above average", above_avg.len());
481
482 // ============================================================================
483 // EXAMPLE 15: Advanced aggregation (revenue calculation)
484 // ============================================================================
485 print_separator("Example 15: Advanced aggregation");
486 print_query(
487 "SELECT \n\
488 d.name,\n\
489 d.budget as dept_budget,\n\
490 SUM(p.budget) as total_project_budget,\n\
491 (d.budget - SUM(p.budget)) as remaining_budget\n\
492 FROM departments d\n\
493 LEFT JOIN projects p ON d.id = p.department_id\n\
494 GROUP BY d.name, d.budget;",
495 "Department budget utilization"
496 );
497
498 // Join departments with projects
499 let dept_projects = JoinQuery::new(&departments, &projects).left_join(
500 Department::id_r(),
501 Project::department_id_r(),
502 |dept, proj| (dept.clone(), proj.map(|p| p.clone())),
503 );
504
505 // Aggregate by department
506 let mut dept_budget_map: HashMap<String, (f64, Vec<f64>)> = HashMap::new();
507 for (dept, proj) in dept_projects {
508 let entry = dept_budget_map
509 .entry(dept.name.clone())
510 .or_insert((dept.budget, Vec::new()));
511 if let Some(p) = proj {
512 entry.1.push(p.budget);
513 }
514 }
515
516 for (dept_name, (total_budget, project_budgets)) in dept_budget_map.iter() {
517 let used: f64 = project_budgets.iter().sum();
518 let remaining = total_budget - used;
519 println!(" {}: Budget ${:.0}, Used ${:.0}, Remaining ${:.0} ({:.1}% utilized)",
520 dept_name, total_budget, used, remaining, (used / total_budget * 100.0));
521 }
522
523 println!("\nRust Query Builder:");
524 println!("let dept_projects = JoinQuery::new(&departments, &projects)");
525 println!(" .left_join(Department::id_r(), Project::department_id_r(), ...)");
526 println!("// Then aggregate using HashMap");
527
528 // ============================================================================
529 // Summary
530 // ============================================================================
531 print_separator("Summary");
532 println!("\n✓ All 15 SQL queries successfully replicated with Rust Query Builder!");
533 println!("\nDemonstrated equivalents for:");
534 println!(" • SELECT with WHERE");
535 println!(" • Projection (SELECT specific columns)");
536 println!(" • Aggregations (COUNT, SUM, AVG, MIN, MAX)");
537 println!(" • GROUP BY");
538 println!(" • ORDER BY");
539 println!(" • LIMIT and OFFSET");
540 println!(" • INNER JOIN and LEFT JOIN");
541 println!(" • Complex conditions (AND, OR, BETWEEN)");
542 println!(" • Subqueries");
543 println!(" • Multi-table operations");
544 println!("\n🎯 Type-safe, compile-time checked, and zero runtime overhead!");
545 println!();
546}Sourcepub fn min_float(&self, path: KeyPaths<T, f64>) -> Option<f64>
pub fn min_float(&self, path: KeyPaths<T, f64>) -> Option<f64>
Finds the minimum value of a float field.
§Arguments
path- The key-path to the f64 field
§Example
let min_price = query.min_float(Product::price_r());Examples found in repository?
28fn main() {
29 println!("╔════════════════════════════════════════════════════════════╗");
30 println!("║ Query Builder Without Clone - Performance Optimization ║");
31 println!("╚════════════════════════════════════════════════════════════╝\n");
32
33 let employees = vec![
34 Employee {
35 id: 1,
36 name: "Alice".to_string(),
37 email: "alice@example.com".to_string(),
38 department: "Engineering".to_string(),
39 salary: 95000.0,
40 large_data: vec![0; 1000], // Large data - expensive to clone!
41 },
42 Employee {
43 id: 2,
44 name: "Bob".to_string(),
45 email: "bob@example.com".to_string(),
46 department: "Engineering".to_string(),
47 salary: 87000.0,
48 large_data: vec![0; 1000],
49 },
50 Employee {
51 id: 3,
52 name: "Carol".to_string(),
53 email: "carol@example.com".to_string(),
54 department: "Sales".to_string(),
55 salary: 75000.0,
56 large_data: vec![0; 1000],
57 },
58 ];
59
60 let departments = vec![
61 Department {
62 id: 1,
63 name: "Engineering".to_string(),
64 budget: 1000000.0,
65 },
66 Department {
67 id: 2,
68 name: "Sales".to_string(),
69 budget: 500000.0,
70 },
71 ];
72
73 println!("✅ Operations that DON'T require Clone:\n");
74
75 // 1. WHERE filtering - returns Vec<&T>
76 println!("1. WHERE filtering (returns references)");
77 let query = Query::new(&employees)
78 .where_(Employee::department_r(), |dept| dept == "Engineering");
79 let engineering = query.all();
80 println!(" Found {} engineering employees", engineering.len());
81 for emp in &engineering {
82 println!(" - {}: ${:.0}", emp.name, emp.salary);
83 }
84
85 // 2. COUNT - no cloning needed
86 println!("\n2. COUNT aggregation");
87 let count = Query::new(&employees)
88 .where_(Employee::salary_r(), |&sal| sal > 80000.0)
89 .count();
90 println!(" {} employees earn over $80k", count);
91
92 // 3. SELECT - only clones the selected field
93 println!("\n3. SELECT (only selected fields are cloned)");
94 let names: Vec<String> = Query::new(&employees)
95 .select(Employee::name_r());
96 println!(" Employee names: {:?}", names);
97
98 // 4. FIRST - returns Option<&T>
99 println!("\n4. FIRST (returns reference)");
100 let query = Query::new(&employees)
101 .where_(Employee::salary_r(), |&sal| sal > 90000.0);
102 if let Some(emp) = query.first() {
103 println!(" First high earner: {} (${:.0})", emp.name, emp.salary);
104 }
105
106 // 5. SUM/AVG aggregations - no cloning
107 println!("\n5. Aggregations (SUM/AVG)");
108 let eng_query = Query::new(&employees)
109 .where_(Employee::department_r(), |dept| dept == "Engineering");
110 let total = eng_query.sum(Employee::salary_r());
111 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
112 println!(" Engineering total: ${:.0}", total);
113 println!(" Engineering average: ${:.0}", avg);
114
115 // 6. MIN/MAX - no cloning
116 println!("\n6. MIN/MAX");
117 let min = Query::new(&employees).min_float(Employee::salary_r());
118 let max = Query::new(&employees).max_float(Employee::salary_r());
119 println!(" Salary range: ${:.0} - ${:.0}", min.unwrap(), max.unwrap());
120
121 // 7. LIMIT - returns Vec<&T>
122 println!("\n7. LIMIT (returns references)");
123 let query = Query::new(&employees);
124 let first_two = query.limit(2);
125 println!(" First 2 employees:");
126 for emp in &first_two {
127 println!(" - {}", emp.name);
128 }
129
130 // 8. SKIP/Pagination - returns Vec<&T>
131 println!("\n8. SKIP/Pagination (returns references)");
132 let query = Query::new(&employees);
133 let page_2 = query.skip(2).limit(1);
134 println!(" Page 2:");
135 for emp in &page_2 {
136 println!(" - {}", emp.name);
137 }
138
139 // 9. EXISTS - just checks
140 println!("\n9. EXISTS check");
141 let has_sales = Query::new(&employees)
142 .where_(Employee::department_r(), |dept| dept == "Sales")
143 .exists();
144 println!(" Has Sales employees: {}", has_sales);
145
146 // 10. JOIN - no Clone required on L or R!
147 println!("\n10. JOIN operations (no Clone required!)");
148 let results = JoinQuery::new(&employees, &departments)
149 .inner_join(
150 Employee::department_r(),
151 Department::name_r(),
152 |emp, dept| {
153 // Mapper only clones what it needs for the result
154 (emp.name.clone(), dept.budget)
155 },
156 );
157 println!(" Employee-Department pairs:");
158 for (name, budget) in &results {
159 println!(" - {} works in dept with ${:.0} budget", name, budget);
160 }
161
162 println!("\n╔════════════════════════════════════════════════════════════╗");
163 println!("║ Operations that REQUIRE Clone (only when needed) ║");
164 println!("╚════════════════════════════════════════════════════════════╝\n");
165
166 println!("⚠️ The following operations require Clone because they return owned Vec<T>:");
167 println!(" - order_by() / order_by_desc()");
168 println!(" - order_by_float() / order_by_float_desc()");
169 println!(" - group_by()");
170 println!("\n To use these, add #[derive(Clone)] to your struct:");
171 println!(" ```rust");
172 println!(" #[derive(Clone, Keypaths)] // Add Clone here");
173 println!(" struct Employee {{ ... }}");
174 println!(" ```");
175
176 println!("\n╔════════════════════════════════════════════════════════════╗");
177 println!("║ Performance Benefits ║");
178 println!("╚════════════════════════════════════════════════════════════╝\n");
179
180 println!("✅ Zero cloning for most operations");
181 println!("✅ Work with large structs efficiently");
182 println!("✅ No unnecessary memory allocations");
183 println!("✅ Only clone when you actually need owned data");
184 println!("✅ Pay for what you use");
185
186 println!("\n✓ Example complete! Most operations work without Clone.\n");
187}More examples
110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}33fn main() {
34 let employees = create_test_data();
35
36 println!("\n╔════════════════════════════════════════════════════════════════╗");
37 println!("║ SQL Equivalence Verification Tests ║");
38 println!("╚════════════════════════════════════════════════════════════════╝\n");
39
40 // TEST 1: ORDER BY maintains exact SQL ordering (DESC)
41 println!("Test 1: ORDER BY DESC - Exact ordering");
42 println!("SQL: SELECT * FROM employees ORDER BY salary DESC;");
43
44 let ordered = Query::new(&employees).order_by_float_desc(Employee::salary_r());
45 let expected_order = vec![105000.0, 95000.0, 87000.0, 82000.0, 75000.0, 71000.0];
46 let actual_order: Vec<f64> = ordered.iter().map(|e| e.salary).collect();
47
48 let test1_pass = expected_order == actual_order;
49 print_test("ORDER BY salary DESC produces correct order", test1_pass);
50 if !test1_pass {
51 println!(" Expected: {:?}", expected_order);
52 println!(" Got: {:?}", actual_order);
53 }
54
55 // TEST 2: ORDER BY maintains exact SQL ordering (ASC)
56 println!("\nTest 2: ORDER BY ASC - Exact ordering");
57 println!("SQL: SELECT * FROM employees ORDER BY salary ASC;");
58
59 let ordered_asc = Query::new(&employees).order_by_float(Employee::salary_r());
60 let expected_asc = vec![71000.0, 75000.0, 82000.0, 87000.0, 95000.0, 105000.0];
61 let actual_asc: Vec<f64> = ordered_asc.iter().map(|e| e.salary).collect();
62
63 let test2_pass = expected_asc == actual_asc;
64 print_test("ORDER BY salary ASC produces correct order", test2_pass);
65 if !test2_pass {
66 println!(" Expected: {:?}", expected_asc);
67 println!(" Got: {:?}", actual_asc);
68 }
69
70 // TEST 3: String ordering (alphabetical)
71 println!("\nTest 3: ORDER BY name (alphabetical)");
72 println!("SQL: SELECT name FROM employees ORDER BY name;");
73
74 let ordered_names = Query::new(&employees).order_by(Employee::name_r());
75 let expected_names = vec!["Alice Cooper", "Alice Johnson", "Bob Smith", "Carol White", "David Brown", "Eve Davis"];
76 let actual_names: Vec<&str> = ordered_names.iter().map(|e| e.name.as_str()).collect();
77
78 let test3_pass = expected_names == actual_names;
79 print_test("ORDER BY name produces correct alphabetical order", test3_pass);
80 if !test3_pass {
81 println!(" Expected: {:?}", expected_names);
82 println!(" Got: {:?}", actual_names);
83 }
84
85 // TEST 4: LIKE equivalent - starts with
86 println!("\nTest 4: LIKE 'Alice%' equivalent");
87 println!("SQL: SELECT * FROM employees WHERE name LIKE 'Alice%';");
88
89 let like_alice_query = Query::new(&employees)
90 .where_(Employee::name_r(), |name| name.starts_with("Alice"));
91 let like_alice = like_alice_query.all();
92
93 let test4_pass = like_alice.len() == 2
94 && like_alice.iter().all(|e| e.name.starts_with("Alice"));
95 print_test("LIKE 'Alice%' (starts_with) works correctly", test4_pass);
96 if test4_pass {
97 for emp in &like_alice {
98 println!(" Found: {}", emp.name);
99 }
100 }
101
102 // TEST 5: LIKE equivalent - ends with
103 println!("\nTest 5: LIKE '%son' equivalent");
104 println!("SQL: SELECT * FROM employees WHERE name LIKE '%son';");
105
106 let like_son_query = Query::new(&employees)
107 .where_(Employee::name_r(), |name| name.ends_with("son"));
108 let like_son = like_son_query.all();
109
110 let test5_pass = like_son.len() == 1 && like_son[0].name == "Alice Johnson";
111 print_test("LIKE '%son' (ends_with) works correctly", test5_pass);
112 if test5_pass {
113 for emp in &like_son {
114 println!(" Found: {}", emp.name);
115 }
116 }
117
118 // TEST 6: LIKE equivalent - contains
119 println!("\nTest 6: LIKE '%mit%' equivalent");
120 println!("SQL: SELECT * FROM employees WHERE name LIKE '%mit%';");
121
122 let like_mit_query = Query::new(&employees)
123 .where_(Employee::name_r(), |name| name.contains("mit"));
124 let like_mit = like_mit_query.all();
125
126 let test6_pass = like_mit.len() == 1 && like_mit[0].name == "Bob Smith";
127 print_test("LIKE '%mit%' (contains) works correctly", test6_pass);
128 if test6_pass {
129 for emp in &like_mit {
130 println!(" Found: {}", emp.name);
131 }
132 }
133
134 // TEST 7: IN clause equivalent
135 println!("\nTest 7: IN clause equivalent");
136 println!("SQL: SELECT * FROM employees WHERE department IN ('Engineering', 'Sales');");
137
138 let in_depts_query = Query::new(&employees)
139 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales");
140 let in_depts = in_depts_query.all();
141
142 let test7_pass = in_depts.len() == 5 // 3 Engineering + 2 Sales
143 && in_depts.iter().all(|e| e.department == "Engineering" || e.department == "Sales");
144 print_test("IN clause works correctly", test7_pass);
145 println!(" Found {} employees in Engineering or Sales", in_depts.len());
146
147 // TEST 8: BETWEEN equivalent
148 println!("\nTest 8: BETWEEN clause equivalent");
149 println!("SQL: SELECT * FROM employees WHERE salary BETWEEN 75000 AND 90000;");
150
151 let between_query = Query::new(&employees)
152 .where_(Employee::salary_r(), |&sal| sal >= 75000.0 && sal <= 90000.0);
153 let between = between_query.all();
154
155 let test8_pass = between.len() == 3;
156 print_test("BETWEEN clause works correctly", test8_pass);
157 println!(" Found {} employees with salary between 75K-90K", between.len());
158
159 // TEST 9: COUNT with WHERE
160 println!("\nTest 9: COUNT with WHERE");
161 println!("SQL: SELECT COUNT(*) FROM employees WHERE department = 'Engineering';");
162
163 let count_eng = Query::new(&employees)
164 .where_(Employee::department_r(), |dept| dept == "Engineering")
165 .count();
166
167 let test9_pass = count_eng == 3;
168 print_test("COUNT with WHERE produces correct result", test9_pass);
169 println!(" Count: {} (expected 3)", count_eng);
170
171 // TEST 10: AVG produces exact result
172 println!("\nTest 10: AVG aggregation accuracy");
173 println!("SQL: SELECT AVG(salary) FROM employees WHERE department = 'Engineering';");
174
175 let avg_sal = Query::new(&employees)
176 .where_(Employee::department_r(), |dept| dept == "Engineering")
177 .avg(Employee::salary_r())
178 .unwrap_or(0.0);
179
180 let expected_avg = (95000.0 + 87000.0 + 105000.0) / 3.0;
181 let test10_pass = (avg_sal - expected_avg).abs() < 0.01;
182 print_test("AVG produces mathematically correct result", test10_pass);
183 println!(" Average: ${:.2} (expected ${:.2})", avg_sal, expected_avg);
184
185 // TEST 11: MIN and MAX
186 println!("\nTest 11: MIN and MAX aggregations");
187 println!("SQL: SELECT MIN(salary), MAX(salary) FROM employees;");
188
189 let min_sal = Query::new(&employees).min_float(Employee::salary_r()).unwrap_or(0.0);
190 let max_sal = Query::new(&employees).max_float(Employee::salary_r()).unwrap_or(0.0);
191
192 let test11_pass = min_sal == 71000.0 && max_sal == 105000.0;
193 print_test("MIN and MAX produce correct results", test11_pass);
194 println!(" MIN: ${:.2}, MAX: ${:.2}", min_sal, max_sal);
195
196 // TEST 12: Complex WHERE with AND/OR
197 println!("\nTest 12: Complex WHERE (AND + OR)");
198 println!("SQL: SELECT * FROM employees WHERE (department = 'Engineering' OR department = 'Sales') AND salary > 80000;");
199
200 let complex_query = Query::new(&employees)
201 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
202 .where_(Employee::salary_r(), |&sal| sal > 80000.0);
203 let complex = complex_query.all();
204
205 let test12_pass = complex.len() == 4; // Alice J ($95k), Bob ($87k), David ($82k), Alice C ($105k)
206 print_test("Complex WHERE clause works correctly", test12_pass);
207 println!(" Found {} employees", complex.len());
208
209 // TEST 13: Case-sensitive string comparison (SQL default)
210 println!("\nTest 13: Case-sensitive comparison (like SQL)");
211 println!("SQL: SELECT * FROM employees WHERE department = 'engineering'; -- should find 0");
212
213 let case_sensitive = Query::new(&employees)
214 .where_(Employee::department_r(), |dept| dept == "engineering") // lowercase
215 .count();
216
217 let test13_pass = case_sensitive == 0;
218 print_test("Case-sensitive comparison (SQL default)", test13_pass);
219 println!(" Found {} with lowercase 'engineering' (expected 0)", case_sensitive);
220
221 // TEST 14: Case-insensitive LIKE equivalent
222 println!("\nTest 14: Case-insensitive LIKE (ILIKE equivalent)");
223 println!("SQL: SELECT * FROM employees WHERE LOWER(name) LIKE '%alice%';");
224
225 let ilike_query = Query::new(&employees)
226 .where_(Employee::name_r(), |name| name.to_lowercase().contains("alice"));
227 let ilike = ilike_query.all();
228
229 let test14_pass = ilike.len() == 2;
230 print_test("Case-insensitive LIKE works correctly", test14_pass);
231 println!(" Found {} employees with 'alice' (case-insensitive)", ilike.len());
232
233 // TEST 15: LIMIT produces exact subset
234 println!("\nTest 15: LIMIT clause");
235 println!("SQL: SELECT * FROM employees ORDER BY salary DESC LIMIT 3;");
236
237 let limited = Query::new(&employees)
238 .order_by_float_desc(Employee::salary_r())
239 .into_iter()
240 .take(3)
241 .collect::<Vec<_>>();
242
243 let test15_pass = limited.len() == 3
244 && limited[0].salary == 105000.0
245 && limited[1].salary == 95000.0
246 && limited[2].salary == 87000.0;
247 print_test("LIMIT returns correct top-N results", test15_pass);
248 println!(" Top 3 salaries: ${:.0}, ${:.0}, ${:.0}",
249 limited[0].salary, limited[1].salary, limited[2].salary);
250
251 // TEST 16: GROUP BY produces correct groups
252 println!("\nTest 16: GROUP BY");
253 println!("SQL: SELECT department, COUNT(*) FROM employees GROUP BY department;");
254
255 let grouped = Query::new(&employees).group_by(Employee::department_r());
256 let eng_count = grouped.get("Engineering").map(|v| v.len()).unwrap_or(0);
257 let sales_count = grouped.get("Sales").map(|v| v.len()).unwrap_or(0);
258 let marketing_count = grouped.get("Marketing").map(|v| v.len()).unwrap_or(0);
259
260 let test16_pass = eng_count == 3 && sales_count == 2 && marketing_count == 1;
261 print_test("GROUP BY produces correct counts", test16_pass);
262 println!(" Engineering: {}, Sales: {}, Marketing: {}", eng_count, sales_count, marketing_count);
263
264 // TEST 17: Email pattern matching (regex-like)
265 println!("\nTest 17: Email domain filtering (LIKE '%@example.com')");
266 println!("SQL: SELECT * FROM employees WHERE email LIKE '%@example.com';");
267
268 let example_emails = Query::new(&employees)
269 .where_(Employee::email_r(), |email| email.ends_with("@example.com"))
270 .count();
271
272 let test17_pass = example_emails == 6; // All employees have @example.com emails
273 print_test("Email pattern matching works correctly", test17_pass);
274 println!(" Found {} employees with @example.com emails", example_emails);
275
276 // Summary
277 println!("\n╔════════════════════════════════════════════════════════════════╗");
278 println!("║ Test Summary ║");
279 println!("╚════════════════════════════════════════════════════════════════╝\n");
280
281 let tests = vec![
282 ("ORDER BY DESC", test1_pass),
283 ("ORDER BY ASC", test2_pass),
284 ("ORDER BY name", test3_pass),
285 ("LIKE 'prefix%'", test4_pass),
286 ("LIKE '%suffix'", test5_pass),
287 ("LIKE '%contains%'", test6_pass),
288 ("IN clause", test7_pass),
289 ("BETWEEN clause", test8_pass),
290 ("COUNT", test9_pass),
291 ("AVG accuracy", test10_pass),
292 ("MIN/MAX", test11_pass),
293 ("Complex WHERE", test12_pass),
294 ("Case-sensitive", test13_pass),
295 ("Case-insensitive", test14_pass),
296 ("LIMIT", test15_pass),
297 ("GROUP BY", test16_pass),
298 ("Email patterns", test17_pass),
299 ];
300
301 let passed = tests.iter().filter(|(_, p)| *p).count();
302 let total = tests.len();
303
304 println!("Results: {}/{} tests passed", passed, total);
305
306 if passed == total {
307 println!("\n🎉 All tests PASSED! Rust Query Builder produces exact SQL-equivalent results!");
308 println!("\n✅ Verified:");
309 println!(" • Exact ordering (ASC/DESC)");
310 println!(" • LIKE operations (starts_with, ends_with, contains)");
311 println!(" • IN clause (OR conditions)");
312 println!(" • BETWEEN clause");
313 println!(" • Aggregations (COUNT, AVG, MIN, MAX)");
314 println!(" • Complex WHERE conditions");
315 println!(" • Case sensitivity");
316 println!(" • LIMIT clause");
317 println!(" • GROUP BY");
318 println!(" • Pattern matching");
319 } else {
320 println!("\n⚠️ {} test(s) failed. See details above.", total - passed);
321 }
322}84fn main() {
85 let employees = create_employees();
86 let departments = create_departments();
87 let projects = create_projects();
88
89 println!("\n╔════════════════════════════════════════════════════════════════════════╗");
90 println!("║ SQL vs Rust Query Builder Comparison ║");
91 println!("║ Demonstrating equivalent operations ║");
92 println!("╚════════════════════════════════════════════════════════════════════════╝");
93
94 // ============================================================================
95 // EXAMPLE 1: Simple SELECT with WHERE
96 // ============================================================================
97 print_separator("Example 1: SELECT with WHERE clause");
98 print_query(
99 "SELECT * FROM employees WHERE department = 'Engineering';",
100 "Filter employees by department"
101 );
102
103 let eng_query = Query::new(&employees)
104 .where_(Employee::department_r(), |dept| dept == "Engineering");
105 let engineering_employees = eng_query.all();
106
107 for emp in &engineering_employees {
108 println!(" ID: {}, Name: {}, Salary: ${:.2}", emp.id, emp.name, emp.salary);
109 }
110 println!("\nRust Query Builder:");
111 println!("Query::new(&employees)");
112 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\")");
113 println!(" .all()");
114 println!("✓ Found {} employees", engineering_employees.len());
115
116 // ============================================================================
117 // EXAMPLE 2: SELECT specific columns
118 // ============================================================================
119 print_separator("Example 2: SELECT specific columns (Projection)");
120 print_query(
121 "SELECT name FROM employees WHERE salary > 80000;",
122 "Get names of high-earning employees"
123 );
124
125 let high_earners = Query::new(&employees)
126 .where_(Employee::salary_r(), |&salary| salary > 80000.0)
127 .select(Employee::name_r());
128
129 for name in &high_earners {
130 println!(" {}", name);
131 }
132 println!("\nRust Query Builder:");
133 println!("Query::new(&employees)");
134 println!(" .where_(Employee::salary_r(), |&salary| salary > 80000.0)");
135 println!(" .select(Employee::name_r())");
136 println!("✓ Found {} employees", high_earners.len());
137
138 // ============================================================================
139 // EXAMPLE 3: COUNT
140 // ============================================================================
141 print_separator("Example 3: COUNT aggregation");
142 print_query(
143 "SELECT COUNT(*) FROM employees WHERE age < 30;",
144 "Count young employees"
145 );
146
147 let young_count = Query::new(&employees)
148 .where_(Employee::age_r(), |&age| age < 30)
149 .count();
150
151 println!(" Count: {}", young_count);
152 println!("\nRust Query Builder:");
153 println!("Query::new(&employees)");
154 println!(" .where_(Employee::age_r(), |&age| age < 30)");
155 println!(" .count()");
156 println!("✓ Result: {}", young_count);
157
158 // ============================================================================
159 // EXAMPLE 4: SUM, AVG, MIN, MAX
160 // ============================================================================
161 print_separator("Example 4: Aggregate functions (SUM, AVG, MIN, MAX)");
162 print_query(
163 "SELECT \n\
164 SUM(salary) as total_salary,\n\
165 AVG(salary) as avg_salary,\n\
166 MIN(salary) as min_salary,\n\
167 MAX(salary) as max_salary\n\
168 FROM employees WHERE department = 'Engineering';",
169 "Engineering department salary statistics"
170 );
171
172 let eng_query = Query::new(&employees)
173 .where_(Employee::department_r(), |dept| dept == "Engineering");
174
175 let total = eng_query.sum(Employee::salary_r());
176 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
177 let min = eng_query.min_float(Employee::salary_r()).unwrap_or(0.0);
178 let max = eng_query.max_float(Employee::salary_r()).unwrap_or(0.0);
179
180 println!(" Total Salary: ${:.2}", total);
181 println!(" Avg Salary: ${:.2}", avg);
182 println!(" Min Salary: ${:.2}", min);
183 println!(" Max Salary: ${:.2}", max);
184
185 println!("\nRust Query Builder:");
186 println!("let query = Query::new(&employees)");
187 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\");");
188 println!("query.sum(Employee::salary_r()) // ${:.2}", total);
189 println!("query.avg(Employee::salary_r()) // ${:.2}", avg);
190 println!("query.min_float(Employee::salary_r()) // ${:.2}", min);
191 println!("query.max_float(Employee::salary_r()) // ${:.2}", max);
192
193 // ============================================================================
194 // EXAMPLE 5: GROUP BY with aggregation
195 // ============================================================================
196 print_separator("Example 5: GROUP BY with aggregation");
197 print_query(
198 "SELECT \n\
199 department,\n\
200 COUNT(*) as emp_count,\n\
201 AVG(salary) as avg_salary\n\
202 FROM employees\n\
203 GROUP BY department;",
204 "Statistics by department"
205 );
206
207 let by_dept = Query::new(&employees).group_by(Employee::department_r());
208
209 for (dept, emps) in &by_dept {
210 let dept_query = Query::new(emps);
211 let count = emps.len();
212 let avg_sal = dept_query.avg(Employee::salary_r()).unwrap_or(0.0);
213 println!(" {}: {} employees, avg salary ${:.2}", dept, count, avg_sal);
214 }
215
216 println!("\nRust Query Builder:");
217 println!("let by_dept = Query::new(&employees).group_by(Employee::department_r());");
218 println!("for (dept, emps) in &by_dept {{");
219 println!(" let dept_query = Query::new(emps);");
220 println!(" dept_query.avg(Employee::salary_r())");
221 println!("}}");
222
223 // ============================================================================
224 // EXAMPLE 6: ORDER BY
225 // ============================================================================
226 print_separator("Example 6: ORDER BY");
227 print_query(
228 "SELECT name, salary FROM employees\n\
229 WHERE department = 'Sales'\n\
230 ORDER BY salary DESC;",
231 "Sales employees ordered by salary (descending)"
232 );
233
234 let sales_sorted = Query::new(&employees)
235 .where_(Employee::department_r(), |dept| dept == "Sales")
236 .order_by_float_desc(Employee::salary_r());
237
238 for emp in &sales_sorted {
239 println!(" {}: ${:.2}", emp.name, emp.salary);
240 }
241
242 println!("\nRust Query Builder:");
243 println!("Query::new(&employees)");
244 println!(" .where_(Employee::department_r(), |dept| dept == \"Sales\")");
245 println!(" .order_by_float_desc(Employee::salary_r())");
246
247 // ============================================================================
248 // EXAMPLE 7: Multiple WHERE conditions (AND)
249 // ============================================================================
250 print_separator("Example 7: Multiple WHERE conditions (AND)");
251 print_query(
252 "SELECT * FROM employees\n\
253 WHERE salary > 70000 AND age < 35;",
254 "High-earning young employees"
255 );
256
257 let filter_query = Query::new(&employees)
258 .where_(Employee::salary_r(), |&salary| salary > 70000.0)
259 .where_(Employee::age_r(), |&age| age < 35);
260 let filtered = filter_query.all();
261
262 for emp in &filtered {
263 println!(" {}: Age {}, Salary ${:.2}", emp.name, emp.age, emp.salary);
264 }
265
266 println!("\nRust Query Builder:");
267 println!("Query::new(&employees)");
268 println!(" .where_(Employee::salary_r(), |&salary| salary > 70000.0)");
269 println!(" .where_(Employee::age_r(), |&age| age < 35)");
270 println!(" .all()");
271 println!("✓ Found {} employees", filtered.len());
272
273 // ============================================================================
274 // EXAMPLE 8: LIMIT (TOP N)
275 // ============================================================================
276 print_separator("Example 8: LIMIT / TOP N");
277 print_query(
278 "SELECT TOP 3 name, salary FROM employees\n\
279 ORDER BY salary DESC;",
280 "Top 3 highest paid employees"
281 );
282
283 let top_earners = Query::new(&employees)
284 .order_by_float_desc(Employee::salary_r());
285
286 for (i, emp) in top_earners.iter().take(3).enumerate() {
287 println!(" {}. {}: ${:.2}", i + 1, emp.name, emp.salary);
288 }
289
290 println!("\nRust Query Builder:");
291 println!("Query::new(&employees)");
292 println!(" .order_by_float_desc(Employee::salary_r())");
293 println!(" .into_iter().take(3)");
294
295 // ============================================================================
296 // EXAMPLE 9: OFFSET and LIMIT (Pagination)
297 // ============================================================================
298 print_separator("Example 9: OFFSET and LIMIT (Pagination)");
299 print_query(
300 "SELECT name FROM employees\n\
301 ORDER BY name\n\
302 LIMIT 3 OFFSET 3;",
303 "Page 2 of employee names (3 per page)"
304 );
305
306 let page_2 = Query::new(&employees)
307 .order_by(Employee::name_r())
308 .into_iter()
309 .skip(3)
310 .take(3)
311 .collect::<Vec<_>>();
312
313 for emp in &page_2 {
314 println!(" {}", emp.name);
315 }
316
317 println!("\nRust Query Builder:");
318 println!("Query::new(&employees)");
319 println!(" .order_by(Employee::name_r())");
320 println!(" .into_iter().skip(3).take(3)");
321
322 // ============================================================================
323 // EXAMPLE 10: INNER JOIN
324 // ============================================================================
325 print_separator("Example 10: INNER JOIN");
326 print_query(
327 "SELECT e.name, d.name as dept_name, d.budget\n\
328 FROM employees e\n\
329 INNER JOIN departments d ON e.department = d.name;",
330 "Employees with their department info"
331 );
332
333 let emp_dept = JoinQuery::new(&employees, &departments).inner_join(
334 Employee::department_r(),
335 Department::name_r(),
336 |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget),
337 );
338
339 for (emp_name, dept_name, budget) in emp_dept.iter().take(5) {
340 println!(" {} works in {} (Budget: ${:.0})", emp_name, dept_name, budget);
341 }
342 println!(" ... (showing first 5)");
343
344 println!("\nRust Query Builder:");
345 println!("JoinQuery::new(&employees, &departments).inner_join(");
346 println!(" Employee::department_r(),");
347 println!(" Department::name_r(),");
348 println!(" |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget)");
349 println!(")");
350 println!("✓ Found {} matches", emp_dept.len());
351
352 // ============================================================================
353 // EXAMPLE 11: GROUP BY with HAVING equivalent
354 // ============================================================================
355 print_separator("Example 11: GROUP BY with filtering (HAVING equivalent)");
356 print_query(
357 "SELECT city, COUNT(*) as emp_count, AVG(salary) as avg_salary\n\
358 FROM employees\n\
359 GROUP BY city\n\
360 HAVING COUNT(*) > 1;",
361 "Cities with multiple employees"
362 );
363
364 let by_city = Query::new(&employees).group_by(Employee::city_r());
365 let mut city_stats: Vec<_> = by_city
366 .iter()
367 .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent
368 .map(|(city, emps)| {
369 let avg_sal = Query::new(emps).avg(Employee::salary_r()).unwrap_or(0.0);
370 (city.clone(), emps.len(), avg_sal)
371 })
372 .collect();
373
374 city_stats.sort_by(|a, b| b.1.cmp(&a.1)); // Sort by count
375
376 for (city, count, avg_sal) in &city_stats {
377 println!(" {}: {} employees, avg salary ${:.2}", city, count, avg_sal);
378 }
379
380 println!("\nRust Query Builder:");
381 println!("let by_city = Query::new(&employees).group_by(Employee::city_r());");
382 println!("by_city.iter()");
383 println!(" .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent");
384 println!(" .map(|(city, emps)| {{");
385 println!(" let avg = Query::new(emps).avg(Employee::salary_r());");
386 println!(" (city, emps.len(), avg)");
387 println!(" }})");
388
389 // ============================================================================
390 // EXAMPLE 12: Complex query with multiple operations
391 // ============================================================================
392 print_separator("Example 12: Complex multi-operation query");
393 print_query(
394 "SELECT name, salary, age\n\
395 FROM employees\n\
396 WHERE department IN ('Engineering', 'Sales')\n\
397 AND salary BETWEEN 80000 AND 100000\n\
398 AND age >= 30\n\
399 ORDER BY salary DESC;",
400 "Experienced mid-to-senior level employees in core departments"
401 );
402
403 let complex_query = Query::new(&employees)
404 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
405 .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)
406 .where_(Employee::age_r(), |&age| age >= 30)
407 .order_by_float_desc(Employee::salary_r());
408
409 for emp in &complex_query {
410 println!(" {}: Age {}, {} dept, ${:.2}", emp.name, emp.age, emp.department, emp.salary);
411 }
412
413 println!("\nRust Query Builder:");
414 println!("Query::new(&employees)");
415 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\" || dept == \"Sales\")");
416 println!(" .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)");
417 println!(" .where_(Employee::age_r(), |&age| age >= 30)");
418 println!(" .order_by_float_desc(Employee::salary_r())");
419 println!("✓ Found {} employees", complex_query.len());
420
421 // ============================================================================
422 // EXAMPLE 13: Three-table JOIN
423 // ============================================================================
424 print_separator("Example 13: Three-table JOIN");
425 print_query(
426 "SELECT p.name as project, d.name as department, d.location\n\
427 FROM projects p\n\
428 INNER JOIN departments d ON p.department_id = d.id;",
429 "Projects with their department details"
430 );
431
432 let proj_dept = JoinQuery::new(&projects, &departments).inner_join(
433 Project::department_id_r(),
434 Department::id_r(),
435 |proj, dept| {
436 (proj.name.clone(), dept.name.clone(), dept.location.clone(), proj.budget)
437 },
438 );
439
440 for (proj_name, dept_name, location, budget) in &proj_dept {
441 println!(" {}: {} dept in {} (${:.0})", proj_name, dept_name, location, budget);
442 }
443
444 println!("\nRust Query Builder:");
445 println!("JoinQuery::new(&projects, &departments).inner_join(");
446 println!(" Project::department_id_r(),");
447 println!(" Department::id_r(),");
448 println!(" |proj, dept| (proj.name, dept.name, dept.location, proj.budget)");
449 println!(")");
450
451 // ============================================================================
452 // EXAMPLE 14: Subquery equivalent (using intermediate results)
453 // ============================================================================
454 print_separator("Example 14: Subquery equivalent");
455 print_query(
456 "SELECT * FROM employees\n\
457 WHERE salary > (SELECT AVG(salary) FROM employees);",
458 "Employees earning above average"
459 );
460
461 let avg_salary = Query::new(&employees)
462 .avg(Employee::salary_r())
463 .unwrap_or(0.0);
464
465 let above_avg_query = Query::new(&employees)
466 .where_(Employee::salary_r(), move |&sal| sal > avg_salary);
467 let above_avg = above_avg_query.all();
468
469 println!(" Average salary: ${:.2}", avg_salary);
470 for emp in &above_avg {
471 println!(" {}: ${:.2} ({:.1}% above average)",
472 emp.name, emp.salary, ((emp.salary - avg_salary) / avg_salary * 100.0));
473 }
474
475 println!("\nRust Query Builder:");
476 println!("let avg = Query::new(&employees).avg(Employee::salary_r()).unwrap_or(0.0);");
477 println!("Query::new(&employees)");
478 println!(" .where_(Employee::salary_r(), |&sal| sal > avg)");
479 println!(" .all()");
480 println!("✓ Found {} employees above average", above_avg.len());
481
482 // ============================================================================
483 // EXAMPLE 15: Advanced aggregation (revenue calculation)
484 // ============================================================================
485 print_separator("Example 15: Advanced aggregation");
486 print_query(
487 "SELECT \n\
488 d.name,\n\
489 d.budget as dept_budget,\n\
490 SUM(p.budget) as total_project_budget,\n\
491 (d.budget - SUM(p.budget)) as remaining_budget\n\
492 FROM departments d\n\
493 LEFT JOIN projects p ON d.id = p.department_id\n\
494 GROUP BY d.name, d.budget;",
495 "Department budget utilization"
496 );
497
498 // Join departments with projects
499 let dept_projects = JoinQuery::new(&departments, &projects).left_join(
500 Department::id_r(),
501 Project::department_id_r(),
502 |dept, proj| (dept.clone(), proj.map(|p| p.clone())),
503 );
504
505 // Aggregate by department
506 let mut dept_budget_map: HashMap<String, (f64, Vec<f64>)> = HashMap::new();
507 for (dept, proj) in dept_projects {
508 let entry = dept_budget_map
509 .entry(dept.name.clone())
510 .or_insert((dept.budget, Vec::new()));
511 if let Some(p) = proj {
512 entry.1.push(p.budget);
513 }
514 }
515
516 for (dept_name, (total_budget, project_budgets)) in dept_budget_map.iter() {
517 let used: f64 = project_budgets.iter().sum();
518 let remaining = total_budget - used;
519 println!(" {}: Budget ${:.0}, Used ${:.0}, Remaining ${:.0} ({:.1}% utilized)",
520 dept_name, total_budget, used, remaining, (used / total_budget * 100.0));
521 }
522
523 println!("\nRust Query Builder:");
524 println!("let dept_projects = JoinQuery::new(&departments, &projects)");
525 println!(" .left_join(Department::id_r(), Project::department_id_r(), ...)");
526 println!("// Then aggregate using HashMap");
527
528 // ============================================================================
529 // Summary
530 // ============================================================================
531 print_separator("Summary");
532 println!("\n✓ All 15 SQL queries successfully replicated with Rust Query Builder!");
533 println!("\nDemonstrated equivalents for:");
534 println!(" • SELECT with WHERE");
535 println!(" • Projection (SELECT specific columns)");
536 println!(" • Aggregations (COUNT, SUM, AVG, MIN, MAX)");
537 println!(" • GROUP BY");
538 println!(" • ORDER BY");
539 println!(" • LIMIT and OFFSET");
540 println!(" • INNER JOIN and LEFT JOIN");
541 println!(" • Complex conditions (AND, OR, BETWEEN)");
542 println!(" • Subqueries");
543 println!(" • Multi-table operations");
544 println!("\n🎯 Type-safe, compile-time checked, and zero runtime overhead!");
545 println!();
546}Sourcepub fn max_float(&self, path: KeyPaths<T, f64>) -> Option<f64>
pub fn max_float(&self, path: KeyPaths<T, f64>) -> Option<f64>
Finds the maximum value of a float field.
§Arguments
path- The key-path to the f64 field
§Example
let max_price = query.max_float(Product::price_r());Examples found in repository?
28fn main() {
29 println!("╔════════════════════════════════════════════════════════════╗");
30 println!("║ Query Builder Without Clone - Performance Optimization ║");
31 println!("╚════════════════════════════════════════════════════════════╝\n");
32
33 let employees = vec![
34 Employee {
35 id: 1,
36 name: "Alice".to_string(),
37 email: "alice@example.com".to_string(),
38 department: "Engineering".to_string(),
39 salary: 95000.0,
40 large_data: vec![0; 1000], // Large data - expensive to clone!
41 },
42 Employee {
43 id: 2,
44 name: "Bob".to_string(),
45 email: "bob@example.com".to_string(),
46 department: "Engineering".to_string(),
47 salary: 87000.0,
48 large_data: vec![0; 1000],
49 },
50 Employee {
51 id: 3,
52 name: "Carol".to_string(),
53 email: "carol@example.com".to_string(),
54 department: "Sales".to_string(),
55 salary: 75000.0,
56 large_data: vec![0; 1000],
57 },
58 ];
59
60 let departments = vec![
61 Department {
62 id: 1,
63 name: "Engineering".to_string(),
64 budget: 1000000.0,
65 },
66 Department {
67 id: 2,
68 name: "Sales".to_string(),
69 budget: 500000.0,
70 },
71 ];
72
73 println!("✅ Operations that DON'T require Clone:\n");
74
75 // 1. WHERE filtering - returns Vec<&T>
76 println!("1. WHERE filtering (returns references)");
77 let query = Query::new(&employees)
78 .where_(Employee::department_r(), |dept| dept == "Engineering");
79 let engineering = query.all();
80 println!(" Found {} engineering employees", engineering.len());
81 for emp in &engineering {
82 println!(" - {}: ${:.0}", emp.name, emp.salary);
83 }
84
85 // 2. COUNT - no cloning needed
86 println!("\n2. COUNT aggregation");
87 let count = Query::new(&employees)
88 .where_(Employee::salary_r(), |&sal| sal > 80000.0)
89 .count();
90 println!(" {} employees earn over $80k", count);
91
92 // 3. SELECT - only clones the selected field
93 println!("\n3. SELECT (only selected fields are cloned)");
94 let names: Vec<String> = Query::new(&employees)
95 .select(Employee::name_r());
96 println!(" Employee names: {:?}", names);
97
98 // 4. FIRST - returns Option<&T>
99 println!("\n4. FIRST (returns reference)");
100 let query = Query::new(&employees)
101 .where_(Employee::salary_r(), |&sal| sal > 90000.0);
102 if let Some(emp) = query.first() {
103 println!(" First high earner: {} (${:.0})", emp.name, emp.salary);
104 }
105
106 // 5. SUM/AVG aggregations - no cloning
107 println!("\n5. Aggregations (SUM/AVG)");
108 let eng_query = Query::new(&employees)
109 .where_(Employee::department_r(), |dept| dept == "Engineering");
110 let total = eng_query.sum(Employee::salary_r());
111 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
112 println!(" Engineering total: ${:.0}", total);
113 println!(" Engineering average: ${:.0}", avg);
114
115 // 6. MIN/MAX - no cloning
116 println!("\n6. MIN/MAX");
117 let min = Query::new(&employees).min_float(Employee::salary_r());
118 let max = Query::new(&employees).max_float(Employee::salary_r());
119 println!(" Salary range: ${:.0} - ${:.0}", min.unwrap(), max.unwrap());
120
121 // 7. LIMIT - returns Vec<&T>
122 println!("\n7. LIMIT (returns references)");
123 let query = Query::new(&employees);
124 let first_two = query.limit(2);
125 println!(" First 2 employees:");
126 for emp in &first_two {
127 println!(" - {}", emp.name);
128 }
129
130 // 8. SKIP/Pagination - returns Vec<&T>
131 println!("\n8. SKIP/Pagination (returns references)");
132 let query = Query::new(&employees);
133 let page_2 = query.skip(2).limit(1);
134 println!(" Page 2:");
135 for emp in &page_2 {
136 println!(" - {}", emp.name);
137 }
138
139 // 9. EXISTS - just checks
140 println!("\n9. EXISTS check");
141 let has_sales = Query::new(&employees)
142 .where_(Employee::department_r(), |dept| dept == "Sales")
143 .exists();
144 println!(" Has Sales employees: {}", has_sales);
145
146 // 10. JOIN - no Clone required on L or R!
147 println!("\n10. JOIN operations (no Clone required!)");
148 let results = JoinQuery::new(&employees, &departments)
149 .inner_join(
150 Employee::department_r(),
151 Department::name_r(),
152 |emp, dept| {
153 // Mapper only clones what it needs for the result
154 (emp.name.clone(), dept.budget)
155 },
156 );
157 println!(" Employee-Department pairs:");
158 for (name, budget) in &results {
159 println!(" - {} works in dept with ${:.0} budget", name, budget);
160 }
161
162 println!("\n╔════════════════════════════════════════════════════════════╗");
163 println!("║ Operations that REQUIRE Clone (only when needed) ║");
164 println!("╚════════════════════════════════════════════════════════════╝\n");
165
166 println!("⚠️ The following operations require Clone because they return owned Vec<T>:");
167 println!(" - order_by() / order_by_desc()");
168 println!(" - order_by_float() / order_by_float_desc()");
169 println!(" - group_by()");
170 println!("\n To use these, add #[derive(Clone)] to your struct:");
171 println!(" ```rust");
172 println!(" #[derive(Clone, Keypaths)] // Add Clone here");
173 println!(" struct Employee {{ ... }}");
174 println!(" ```");
175
176 println!("\n╔════════════════════════════════════════════════════════════╗");
177 println!("║ Performance Benefits ║");
178 println!("╚════════════════════════════════════════════════════════════╝\n");
179
180 println!("✅ Zero cloning for most operations");
181 println!("✅ Work with large structs efficiently");
182 println!("✅ No unnecessary memory allocations");
183 println!("✅ Only clone when you actually need owned data");
184 println!("✅ Pay for what you use");
185
186 println!("\n✓ Example complete! Most operations work without Clone.\n");
187}More examples
110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}33fn main() {
34 let employees = create_test_data();
35
36 println!("\n╔════════════════════════════════════════════════════════════════╗");
37 println!("║ SQL Equivalence Verification Tests ║");
38 println!("╚════════════════════════════════════════════════════════════════╝\n");
39
40 // TEST 1: ORDER BY maintains exact SQL ordering (DESC)
41 println!("Test 1: ORDER BY DESC - Exact ordering");
42 println!("SQL: SELECT * FROM employees ORDER BY salary DESC;");
43
44 let ordered = Query::new(&employees).order_by_float_desc(Employee::salary_r());
45 let expected_order = vec![105000.0, 95000.0, 87000.0, 82000.0, 75000.0, 71000.0];
46 let actual_order: Vec<f64> = ordered.iter().map(|e| e.salary).collect();
47
48 let test1_pass = expected_order == actual_order;
49 print_test("ORDER BY salary DESC produces correct order", test1_pass);
50 if !test1_pass {
51 println!(" Expected: {:?}", expected_order);
52 println!(" Got: {:?}", actual_order);
53 }
54
55 // TEST 2: ORDER BY maintains exact SQL ordering (ASC)
56 println!("\nTest 2: ORDER BY ASC - Exact ordering");
57 println!("SQL: SELECT * FROM employees ORDER BY salary ASC;");
58
59 let ordered_asc = Query::new(&employees).order_by_float(Employee::salary_r());
60 let expected_asc = vec![71000.0, 75000.0, 82000.0, 87000.0, 95000.0, 105000.0];
61 let actual_asc: Vec<f64> = ordered_asc.iter().map(|e| e.salary).collect();
62
63 let test2_pass = expected_asc == actual_asc;
64 print_test("ORDER BY salary ASC produces correct order", test2_pass);
65 if !test2_pass {
66 println!(" Expected: {:?}", expected_asc);
67 println!(" Got: {:?}", actual_asc);
68 }
69
70 // TEST 3: String ordering (alphabetical)
71 println!("\nTest 3: ORDER BY name (alphabetical)");
72 println!("SQL: SELECT name FROM employees ORDER BY name;");
73
74 let ordered_names = Query::new(&employees).order_by(Employee::name_r());
75 let expected_names = vec!["Alice Cooper", "Alice Johnson", "Bob Smith", "Carol White", "David Brown", "Eve Davis"];
76 let actual_names: Vec<&str> = ordered_names.iter().map(|e| e.name.as_str()).collect();
77
78 let test3_pass = expected_names == actual_names;
79 print_test("ORDER BY name produces correct alphabetical order", test3_pass);
80 if !test3_pass {
81 println!(" Expected: {:?}", expected_names);
82 println!(" Got: {:?}", actual_names);
83 }
84
85 // TEST 4: LIKE equivalent - starts with
86 println!("\nTest 4: LIKE 'Alice%' equivalent");
87 println!("SQL: SELECT * FROM employees WHERE name LIKE 'Alice%';");
88
89 let like_alice_query = Query::new(&employees)
90 .where_(Employee::name_r(), |name| name.starts_with("Alice"));
91 let like_alice = like_alice_query.all();
92
93 let test4_pass = like_alice.len() == 2
94 && like_alice.iter().all(|e| e.name.starts_with("Alice"));
95 print_test("LIKE 'Alice%' (starts_with) works correctly", test4_pass);
96 if test4_pass {
97 for emp in &like_alice {
98 println!(" Found: {}", emp.name);
99 }
100 }
101
102 // TEST 5: LIKE equivalent - ends with
103 println!("\nTest 5: LIKE '%son' equivalent");
104 println!("SQL: SELECT * FROM employees WHERE name LIKE '%son';");
105
106 let like_son_query = Query::new(&employees)
107 .where_(Employee::name_r(), |name| name.ends_with("son"));
108 let like_son = like_son_query.all();
109
110 let test5_pass = like_son.len() == 1 && like_son[0].name == "Alice Johnson";
111 print_test("LIKE '%son' (ends_with) works correctly", test5_pass);
112 if test5_pass {
113 for emp in &like_son {
114 println!(" Found: {}", emp.name);
115 }
116 }
117
118 // TEST 6: LIKE equivalent - contains
119 println!("\nTest 6: LIKE '%mit%' equivalent");
120 println!("SQL: SELECT * FROM employees WHERE name LIKE '%mit%';");
121
122 let like_mit_query = Query::new(&employees)
123 .where_(Employee::name_r(), |name| name.contains("mit"));
124 let like_mit = like_mit_query.all();
125
126 let test6_pass = like_mit.len() == 1 && like_mit[0].name == "Bob Smith";
127 print_test("LIKE '%mit%' (contains) works correctly", test6_pass);
128 if test6_pass {
129 for emp in &like_mit {
130 println!(" Found: {}", emp.name);
131 }
132 }
133
134 // TEST 7: IN clause equivalent
135 println!("\nTest 7: IN clause equivalent");
136 println!("SQL: SELECT * FROM employees WHERE department IN ('Engineering', 'Sales');");
137
138 let in_depts_query = Query::new(&employees)
139 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales");
140 let in_depts = in_depts_query.all();
141
142 let test7_pass = in_depts.len() == 5 // 3 Engineering + 2 Sales
143 && in_depts.iter().all(|e| e.department == "Engineering" || e.department == "Sales");
144 print_test("IN clause works correctly", test7_pass);
145 println!(" Found {} employees in Engineering or Sales", in_depts.len());
146
147 // TEST 8: BETWEEN equivalent
148 println!("\nTest 8: BETWEEN clause equivalent");
149 println!("SQL: SELECT * FROM employees WHERE salary BETWEEN 75000 AND 90000;");
150
151 let between_query = Query::new(&employees)
152 .where_(Employee::salary_r(), |&sal| sal >= 75000.0 && sal <= 90000.0);
153 let between = between_query.all();
154
155 let test8_pass = between.len() == 3;
156 print_test("BETWEEN clause works correctly", test8_pass);
157 println!(" Found {} employees with salary between 75K-90K", between.len());
158
159 // TEST 9: COUNT with WHERE
160 println!("\nTest 9: COUNT with WHERE");
161 println!("SQL: SELECT COUNT(*) FROM employees WHERE department = 'Engineering';");
162
163 let count_eng = Query::new(&employees)
164 .where_(Employee::department_r(), |dept| dept == "Engineering")
165 .count();
166
167 let test9_pass = count_eng == 3;
168 print_test("COUNT with WHERE produces correct result", test9_pass);
169 println!(" Count: {} (expected 3)", count_eng);
170
171 // TEST 10: AVG produces exact result
172 println!("\nTest 10: AVG aggregation accuracy");
173 println!("SQL: SELECT AVG(salary) FROM employees WHERE department = 'Engineering';");
174
175 let avg_sal = Query::new(&employees)
176 .where_(Employee::department_r(), |dept| dept == "Engineering")
177 .avg(Employee::salary_r())
178 .unwrap_or(0.0);
179
180 let expected_avg = (95000.0 + 87000.0 + 105000.0) / 3.0;
181 let test10_pass = (avg_sal - expected_avg).abs() < 0.01;
182 print_test("AVG produces mathematically correct result", test10_pass);
183 println!(" Average: ${:.2} (expected ${:.2})", avg_sal, expected_avg);
184
185 // TEST 11: MIN and MAX
186 println!("\nTest 11: MIN and MAX aggregations");
187 println!("SQL: SELECT MIN(salary), MAX(salary) FROM employees;");
188
189 let min_sal = Query::new(&employees).min_float(Employee::salary_r()).unwrap_or(0.0);
190 let max_sal = Query::new(&employees).max_float(Employee::salary_r()).unwrap_or(0.0);
191
192 let test11_pass = min_sal == 71000.0 && max_sal == 105000.0;
193 print_test("MIN and MAX produce correct results", test11_pass);
194 println!(" MIN: ${:.2}, MAX: ${:.2}", min_sal, max_sal);
195
196 // TEST 12: Complex WHERE with AND/OR
197 println!("\nTest 12: Complex WHERE (AND + OR)");
198 println!("SQL: SELECT * FROM employees WHERE (department = 'Engineering' OR department = 'Sales') AND salary > 80000;");
199
200 let complex_query = Query::new(&employees)
201 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
202 .where_(Employee::salary_r(), |&sal| sal > 80000.0);
203 let complex = complex_query.all();
204
205 let test12_pass = complex.len() == 4; // Alice J ($95k), Bob ($87k), David ($82k), Alice C ($105k)
206 print_test("Complex WHERE clause works correctly", test12_pass);
207 println!(" Found {} employees", complex.len());
208
209 // TEST 13: Case-sensitive string comparison (SQL default)
210 println!("\nTest 13: Case-sensitive comparison (like SQL)");
211 println!("SQL: SELECT * FROM employees WHERE department = 'engineering'; -- should find 0");
212
213 let case_sensitive = Query::new(&employees)
214 .where_(Employee::department_r(), |dept| dept == "engineering") // lowercase
215 .count();
216
217 let test13_pass = case_sensitive == 0;
218 print_test("Case-sensitive comparison (SQL default)", test13_pass);
219 println!(" Found {} with lowercase 'engineering' (expected 0)", case_sensitive);
220
221 // TEST 14: Case-insensitive LIKE equivalent
222 println!("\nTest 14: Case-insensitive LIKE (ILIKE equivalent)");
223 println!("SQL: SELECT * FROM employees WHERE LOWER(name) LIKE '%alice%';");
224
225 let ilike_query = Query::new(&employees)
226 .where_(Employee::name_r(), |name| name.to_lowercase().contains("alice"));
227 let ilike = ilike_query.all();
228
229 let test14_pass = ilike.len() == 2;
230 print_test("Case-insensitive LIKE works correctly", test14_pass);
231 println!(" Found {} employees with 'alice' (case-insensitive)", ilike.len());
232
233 // TEST 15: LIMIT produces exact subset
234 println!("\nTest 15: LIMIT clause");
235 println!("SQL: SELECT * FROM employees ORDER BY salary DESC LIMIT 3;");
236
237 let limited = Query::new(&employees)
238 .order_by_float_desc(Employee::salary_r())
239 .into_iter()
240 .take(3)
241 .collect::<Vec<_>>();
242
243 let test15_pass = limited.len() == 3
244 && limited[0].salary == 105000.0
245 && limited[1].salary == 95000.0
246 && limited[2].salary == 87000.0;
247 print_test("LIMIT returns correct top-N results", test15_pass);
248 println!(" Top 3 salaries: ${:.0}, ${:.0}, ${:.0}",
249 limited[0].salary, limited[1].salary, limited[2].salary);
250
251 // TEST 16: GROUP BY produces correct groups
252 println!("\nTest 16: GROUP BY");
253 println!("SQL: SELECT department, COUNT(*) FROM employees GROUP BY department;");
254
255 let grouped = Query::new(&employees).group_by(Employee::department_r());
256 let eng_count = grouped.get("Engineering").map(|v| v.len()).unwrap_or(0);
257 let sales_count = grouped.get("Sales").map(|v| v.len()).unwrap_or(0);
258 let marketing_count = grouped.get("Marketing").map(|v| v.len()).unwrap_or(0);
259
260 let test16_pass = eng_count == 3 && sales_count == 2 && marketing_count == 1;
261 print_test("GROUP BY produces correct counts", test16_pass);
262 println!(" Engineering: {}, Sales: {}, Marketing: {}", eng_count, sales_count, marketing_count);
263
264 // TEST 17: Email pattern matching (regex-like)
265 println!("\nTest 17: Email domain filtering (LIKE '%@example.com')");
266 println!("SQL: SELECT * FROM employees WHERE email LIKE '%@example.com';");
267
268 let example_emails = Query::new(&employees)
269 .where_(Employee::email_r(), |email| email.ends_with("@example.com"))
270 .count();
271
272 let test17_pass = example_emails == 6; // All employees have @example.com emails
273 print_test("Email pattern matching works correctly", test17_pass);
274 println!(" Found {} employees with @example.com emails", example_emails);
275
276 // Summary
277 println!("\n╔════════════════════════════════════════════════════════════════╗");
278 println!("║ Test Summary ║");
279 println!("╚════════════════════════════════════════════════════════════════╝\n");
280
281 let tests = vec![
282 ("ORDER BY DESC", test1_pass),
283 ("ORDER BY ASC", test2_pass),
284 ("ORDER BY name", test3_pass),
285 ("LIKE 'prefix%'", test4_pass),
286 ("LIKE '%suffix'", test5_pass),
287 ("LIKE '%contains%'", test6_pass),
288 ("IN clause", test7_pass),
289 ("BETWEEN clause", test8_pass),
290 ("COUNT", test9_pass),
291 ("AVG accuracy", test10_pass),
292 ("MIN/MAX", test11_pass),
293 ("Complex WHERE", test12_pass),
294 ("Case-sensitive", test13_pass),
295 ("Case-insensitive", test14_pass),
296 ("LIMIT", test15_pass),
297 ("GROUP BY", test16_pass),
298 ("Email patterns", test17_pass),
299 ];
300
301 let passed = tests.iter().filter(|(_, p)| *p).count();
302 let total = tests.len();
303
304 println!("Results: {}/{} tests passed", passed, total);
305
306 if passed == total {
307 println!("\n🎉 All tests PASSED! Rust Query Builder produces exact SQL-equivalent results!");
308 println!("\n✅ Verified:");
309 println!(" • Exact ordering (ASC/DESC)");
310 println!(" • LIKE operations (starts_with, ends_with, contains)");
311 println!(" • IN clause (OR conditions)");
312 println!(" • BETWEEN clause");
313 println!(" • Aggregations (COUNT, AVG, MIN, MAX)");
314 println!(" • Complex WHERE conditions");
315 println!(" • Case sensitivity");
316 println!(" • LIMIT clause");
317 println!(" • GROUP BY");
318 println!(" • Pattern matching");
319 } else {
320 println!("\n⚠️ {} test(s) failed. See details above.", total - passed);
321 }
322}84fn main() {
85 let employees = create_employees();
86 let departments = create_departments();
87 let projects = create_projects();
88
89 println!("\n╔════════════════════════════════════════════════════════════════════════╗");
90 println!("║ SQL vs Rust Query Builder Comparison ║");
91 println!("║ Demonstrating equivalent operations ║");
92 println!("╚════════════════════════════════════════════════════════════════════════╝");
93
94 // ============================================================================
95 // EXAMPLE 1: Simple SELECT with WHERE
96 // ============================================================================
97 print_separator("Example 1: SELECT with WHERE clause");
98 print_query(
99 "SELECT * FROM employees WHERE department = 'Engineering';",
100 "Filter employees by department"
101 );
102
103 let eng_query = Query::new(&employees)
104 .where_(Employee::department_r(), |dept| dept == "Engineering");
105 let engineering_employees = eng_query.all();
106
107 for emp in &engineering_employees {
108 println!(" ID: {}, Name: {}, Salary: ${:.2}", emp.id, emp.name, emp.salary);
109 }
110 println!("\nRust Query Builder:");
111 println!("Query::new(&employees)");
112 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\")");
113 println!(" .all()");
114 println!("✓ Found {} employees", engineering_employees.len());
115
116 // ============================================================================
117 // EXAMPLE 2: SELECT specific columns
118 // ============================================================================
119 print_separator("Example 2: SELECT specific columns (Projection)");
120 print_query(
121 "SELECT name FROM employees WHERE salary > 80000;",
122 "Get names of high-earning employees"
123 );
124
125 let high_earners = Query::new(&employees)
126 .where_(Employee::salary_r(), |&salary| salary > 80000.0)
127 .select(Employee::name_r());
128
129 for name in &high_earners {
130 println!(" {}", name);
131 }
132 println!("\nRust Query Builder:");
133 println!("Query::new(&employees)");
134 println!(" .where_(Employee::salary_r(), |&salary| salary > 80000.0)");
135 println!(" .select(Employee::name_r())");
136 println!("✓ Found {} employees", high_earners.len());
137
138 // ============================================================================
139 // EXAMPLE 3: COUNT
140 // ============================================================================
141 print_separator("Example 3: COUNT aggregation");
142 print_query(
143 "SELECT COUNT(*) FROM employees WHERE age < 30;",
144 "Count young employees"
145 );
146
147 let young_count = Query::new(&employees)
148 .where_(Employee::age_r(), |&age| age < 30)
149 .count();
150
151 println!(" Count: {}", young_count);
152 println!("\nRust Query Builder:");
153 println!("Query::new(&employees)");
154 println!(" .where_(Employee::age_r(), |&age| age < 30)");
155 println!(" .count()");
156 println!("✓ Result: {}", young_count);
157
158 // ============================================================================
159 // EXAMPLE 4: SUM, AVG, MIN, MAX
160 // ============================================================================
161 print_separator("Example 4: Aggregate functions (SUM, AVG, MIN, MAX)");
162 print_query(
163 "SELECT \n\
164 SUM(salary) as total_salary,\n\
165 AVG(salary) as avg_salary,\n\
166 MIN(salary) as min_salary,\n\
167 MAX(salary) as max_salary\n\
168 FROM employees WHERE department = 'Engineering';",
169 "Engineering department salary statistics"
170 );
171
172 let eng_query = Query::new(&employees)
173 .where_(Employee::department_r(), |dept| dept == "Engineering");
174
175 let total = eng_query.sum(Employee::salary_r());
176 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
177 let min = eng_query.min_float(Employee::salary_r()).unwrap_or(0.0);
178 let max = eng_query.max_float(Employee::salary_r()).unwrap_or(0.0);
179
180 println!(" Total Salary: ${:.2}", total);
181 println!(" Avg Salary: ${:.2}", avg);
182 println!(" Min Salary: ${:.2}", min);
183 println!(" Max Salary: ${:.2}", max);
184
185 println!("\nRust Query Builder:");
186 println!("let query = Query::new(&employees)");
187 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\");");
188 println!("query.sum(Employee::salary_r()) // ${:.2}", total);
189 println!("query.avg(Employee::salary_r()) // ${:.2}", avg);
190 println!("query.min_float(Employee::salary_r()) // ${:.2}", min);
191 println!("query.max_float(Employee::salary_r()) // ${:.2}", max);
192
193 // ============================================================================
194 // EXAMPLE 5: GROUP BY with aggregation
195 // ============================================================================
196 print_separator("Example 5: GROUP BY with aggregation");
197 print_query(
198 "SELECT \n\
199 department,\n\
200 COUNT(*) as emp_count,\n\
201 AVG(salary) as avg_salary\n\
202 FROM employees\n\
203 GROUP BY department;",
204 "Statistics by department"
205 );
206
207 let by_dept = Query::new(&employees).group_by(Employee::department_r());
208
209 for (dept, emps) in &by_dept {
210 let dept_query = Query::new(emps);
211 let count = emps.len();
212 let avg_sal = dept_query.avg(Employee::salary_r()).unwrap_or(0.0);
213 println!(" {}: {} employees, avg salary ${:.2}", dept, count, avg_sal);
214 }
215
216 println!("\nRust Query Builder:");
217 println!("let by_dept = Query::new(&employees).group_by(Employee::department_r());");
218 println!("for (dept, emps) in &by_dept {{");
219 println!(" let dept_query = Query::new(emps);");
220 println!(" dept_query.avg(Employee::salary_r())");
221 println!("}}");
222
223 // ============================================================================
224 // EXAMPLE 6: ORDER BY
225 // ============================================================================
226 print_separator("Example 6: ORDER BY");
227 print_query(
228 "SELECT name, salary FROM employees\n\
229 WHERE department = 'Sales'\n\
230 ORDER BY salary DESC;",
231 "Sales employees ordered by salary (descending)"
232 );
233
234 let sales_sorted = Query::new(&employees)
235 .where_(Employee::department_r(), |dept| dept == "Sales")
236 .order_by_float_desc(Employee::salary_r());
237
238 for emp in &sales_sorted {
239 println!(" {}: ${:.2}", emp.name, emp.salary);
240 }
241
242 println!("\nRust Query Builder:");
243 println!("Query::new(&employees)");
244 println!(" .where_(Employee::department_r(), |dept| dept == \"Sales\")");
245 println!(" .order_by_float_desc(Employee::salary_r())");
246
247 // ============================================================================
248 // EXAMPLE 7: Multiple WHERE conditions (AND)
249 // ============================================================================
250 print_separator("Example 7: Multiple WHERE conditions (AND)");
251 print_query(
252 "SELECT * FROM employees\n\
253 WHERE salary > 70000 AND age < 35;",
254 "High-earning young employees"
255 );
256
257 let filter_query = Query::new(&employees)
258 .where_(Employee::salary_r(), |&salary| salary > 70000.0)
259 .where_(Employee::age_r(), |&age| age < 35);
260 let filtered = filter_query.all();
261
262 for emp in &filtered {
263 println!(" {}: Age {}, Salary ${:.2}", emp.name, emp.age, emp.salary);
264 }
265
266 println!("\nRust Query Builder:");
267 println!("Query::new(&employees)");
268 println!(" .where_(Employee::salary_r(), |&salary| salary > 70000.0)");
269 println!(" .where_(Employee::age_r(), |&age| age < 35)");
270 println!(" .all()");
271 println!("✓ Found {} employees", filtered.len());
272
273 // ============================================================================
274 // EXAMPLE 8: LIMIT (TOP N)
275 // ============================================================================
276 print_separator("Example 8: LIMIT / TOP N");
277 print_query(
278 "SELECT TOP 3 name, salary FROM employees\n\
279 ORDER BY salary DESC;",
280 "Top 3 highest paid employees"
281 );
282
283 let top_earners = Query::new(&employees)
284 .order_by_float_desc(Employee::salary_r());
285
286 for (i, emp) in top_earners.iter().take(3).enumerate() {
287 println!(" {}. {}: ${:.2}", i + 1, emp.name, emp.salary);
288 }
289
290 println!("\nRust Query Builder:");
291 println!("Query::new(&employees)");
292 println!(" .order_by_float_desc(Employee::salary_r())");
293 println!(" .into_iter().take(3)");
294
295 // ============================================================================
296 // EXAMPLE 9: OFFSET and LIMIT (Pagination)
297 // ============================================================================
298 print_separator("Example 9: OFFSET and LIMIT (Pagination)");
299 print_query(
300 "SELECT name FROM employees\n\
301 ORDER BY name\n\
302 LIMIT 3 OFFSET 3;",
303 "Page 2 of employee names (3 per page)"
304 );
305
306 let page_2 = Query::new(&employees)
307 .order_by(Employee::name_r())
308 .into_iter()
309 .skip(3)
310 .take(3)
311 .collect::<Vec<_>>();
312
313 for emp in &page_2 {
314 println!(" {}", emp.name);
315 }
316
317 println!("\nRust Query Builder:");
318 println!("Query::new(&employees)");
319 println!(" .order_by(Employee::name_r())");
320 println!(" .into_iter().skip(3).take(3)");
321
322 // ============================================================================
323 // EXAMPLE 10: INNER JOIN
324 // ============================================================================
325 print_separator("Example 10: INNER JOIN");
326 print_query(
327 "SELECT e.name, d.name as dept_name, d.budget\n\
328 FROM employees e\n\
329 INNER JOIN departments d ON e.department = d.name;",
330 "Employees with their department info"
331 );
332
333 let emp_dept = JoinQuery::new(&employees, &departments).inner_join(
334 Employee::department_r(),
335 Department::name_r(),
336 |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget),
337 );
338
339 for (emp_name, dept_name, budget) in emp_dept.iter().take(5) {
340 println!(" {} works in {} (Budget: ${:.0})", emp_name, dept_name, budget);
341 }
342 println!(" ... (showing first 5)");
343
344 println!("\nRust Query Builder:");
345 println!("JoinQuery::new(&employees, &departments).inner_join(");
346 println!(" Employee::department_r(),");
347 println!(" Department::name_r(),");
348 println!(" |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget)");
349 println!(")");
350 println!("✓ Found {} matches", emp_dept.len());
351
352 // ============================================================================
353 // EXAMPLE 11: GROUP BY with HAVING equivalent
354 // ============================================================================
355 print_separator("Example 11: GROUP BY with filtering (HAVING equivalent)");
356 print_query(
357 "SELECT city, COUNT(*) as emp_count, AVG(salary) as avg_salary\n\
358 FROM employees\n\
359 GROUP BY city\n\
360 HAVING COUNT(*) > 1;",
361 "Cities with multiple employees"
362 );
363
364 let by_city = Query::new(&employees).group_by(Employee::city_r());
365 let mut city_stats: Vec<_> = by_city
366 .iter()
367 .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent
368 .map(|(city, emps)| {
369 let avg_sal = Query::new(emps).avg(Employee::salary_r()).unwrap_or(0.0);
370 (city.clone(), emps.len(), avg_sal)
371 })
372 .collect();
373
374 city_stats.sort_by(|a, b| b.1.cmp(&a.1)); // Sort by count
375
376 for (city, count, avg_sal) in &city_stats {
377 println!(" {}: {} employees, avg salary ${:.2}", city, count, avg_sal);
378 }
379
380 println!("\nRust Query Builder:");
381 println!("let by_city = Query::new(&employees).group_by(Employee::city_r());");
382 println!("by_city.iter()");
383 println!(" .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent");
384 println!(" .map(|(city, emps)| {{");
385 println!(" let avg = Query::new(emps).avg(Employee::salary_r());");
386 println!(" (city, emps.len(), avg)");
387 println!(" }})");
388
389 // ============================================================================
390 // EXAMPLE 12: Complex query with multiple operations
391 // ============================================================================
392 print_separator("Example 12: Complex multi-operation query");
393 print_query(
394 "SELECT name, salary, age\n\
395 FROM employees\n\
396 WHERE department IN ('Engineering', 'Sales')\n\
397 AND salary BETWEEN 80000 AND 100000\n\
398 AND age >= 30\n\
399 ORDER BY salary DESC;",
400 "Experienced mid-to-senior level employees in core departments"
401 );
402
403 let complex_query = Query::new(&employees)
404 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
405 .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)
406 .where_(Employee::age_r(), |&age| age >= 30)
407 .order_by_float_desc(Employee::salary_r());
408
409 for emp in &complex_query {
410 println!(" {}: Age {}, {} dept, ${:.2}", emp.name, emp.age, emp.department, emp.salary);
411 }
412
413 println!("\nRust Query Builder:");
414 println!("Query::new(&employees)");
415 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\" || dept == \"Sales\")");
416 println!(" .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)");
417 println!(" .where_(Employee::age_r(), |&age| age >= 30)");
418 println!(" .order_by_float_desc(Employee::salary_r())");
419 println!("✓ Found {} employees", complex_query.len());
420
421 // ============================================================================
422 // EXAMPLE 13: Three-table JOIN
423 // ============================================================================
424 print_separator("Example 13: Three-table JOIN");
425 print_query(
426 "SELECT p.name as project, d.name as department, d.location\n\
427 FROM projects p\n\
428 INNER JOIN departments d ON p.department_id = d.id;",
429 "Projects with their department details"
430 );
431
432 let proj_dept = JoinQuery::new(&projects, &departments).inner_join(
433 Project::department_id_r(),
434 Department::id_r(),
435 |proj, dept| {
436 (proj.name.clone(), dept.name.clone(), dept.location.clone(), proj.budget)
437 },
438 );
439
440 for (proj_name, dept_name, location, budget) in &proj_dept {
441 println!(" {}: {} dept in {} (${:.0})", proj_name, dept_name, location, budget);
442 }
443
444 println!("\nRust Query Builder:");
445 println!("JoinQuery::new(&projects, &departments).inner_join(");
446 println!(" Project::department_id_r(),");
447 println!(" Department::id_r(),");
448 println!(" |proj, dept| (proj.name, dept.name, dept.location, proj.budget)");
449 println!(")");
450
451 // ============================================================================
452 // EXAMPLE 14: Subquery equivalent (using intermediate results)
453 // ============================================================================
454 print_separator("Example 14: Subquery equivalent");
455 print_query(
456 "SELECT * FROM employees\n\
457 WHERE salary > (SELECT AVG(salary) FROM employees);",
458 "Employees earning above average"
459 );
460
461 let avg_salary = Query::new(&employees)
462 .avg(Employee::salary_r())
463 .unwrap_or(0.0);
464
465 let above_avg_query = Query::new(&employees)
466 .where_(Employee::salary_r(), move |&sal| sal > avg_salary);
467 let above_avg = above_avg_query.all();
468
469 println!(" Average salary: ${:.2}", avg_salary);
470 for emp in &above_avg {
471 println!(" {}: ${:.2} ({:.1}% above average)",
472 emp.name, emp.salary, ((emp.salary - avg_salary) / avg_salary * 100.0));
473 }
474
475 println!("\nRust Query Builder:");
476 println!("let avg = Query::new(&employees).avg(Employee::salary_r()).unwrap_or(0.0);");
477 println!("Query::new(&employees)");
478 println!(" .where_(Employee::salary_r(), |&sal| sal > avg)");
479 println!(" .all()");
480 println!("✓ Found {} employees above average", above_avg.len());
481
482 // ============================================================================
483 // EXAMPLE 15: Advanced aggregation (revenue calculation)
484 // ============================================================================
485 print_separator("Example 15: Advanced aggregation");
486 print_query(
487 "SELECT \n\
488 d.name,\n\
489 d.budget as dept_budget,\n\
490 SUM(p.budget) as total_project_budget,\n\
491 (d.budget - SUM(p.budget)) as remaining_budget\n\
492 FROM departments d\n\
493 LEFT JOIN projects p ON d.id = p.department_id\n\
494 GROUP BY d.name, d.budget;",
495 "Department budget utilization"
496 );
497
498 // Join departments with projects
499 let dept_projects = JoinQuery::new(&departments, &projects).left_join(
500 Department::id_r(),
501 Project::department_id_r(),
502 |dept, proj| (dept.clone(), proj.map(|p| p.clone())),
503 );
504
505 // Aggregate by department
506 let mut dept_budget_map: HashMap<String, (f64, Vec<f64>)> = HashMap::new();
507 for (dept, proj) in dept_projects {
508 let entry = dept_budget_map
509 .entry(dept.name.clone())
510 .or_insert((dept.budget, Vec::new()));
511 if let Some(p) = proj {
512 entry.1.push(p.budget);
513 }
514 }
515
516 for (dept_name, (total_budget, project_budgets)) in dept_budget_map.iter() {
517 let used: f64 = project_budgets.iter().sum();
518 let remaining = total_budget - used;
519 println!(" {}: Budget ${:.0}, Used ${:.0}, Remaining ${:.0} ({:.1}% utilized)",
520 dept_name, total_budget, used, remaining, (used / total_budget * 100.0));
521 }
522
523 println!("\nRust Query Builder:");
524 println!("let dept_projects = JoinQuery::new(&departments, &projects)");
525 println!(" .left_join(Department::id_r(), Project::department_id_r(), ...)");
526 println!("// Then aggregate using HashMap");
527
528 // ============================================================================
529 // Summary
530 // ============================================================================
531 print_separator("Summary");
532 println!("\n✓ All 15 SQL queries successfully replicated with Rust Query Builder!");
533 println!("\nDemonstrated equivalents for:");
534 println!(" • SELECT with WHERE");
535 println!(" • Projection (SELECT specific columns)");
536 println!(" • Aggregations (COUNT, SUM, AVG, MIN, MAX)");
537 println!(" • GROUP BY");
538 println!(" • ORDER BY");
539 println!(" • LIMIT and OFFSET");
540 println!(" • INNER JOIN and LEFT JOIN");
541 println!(" • Complex conditions (AND, OR, BETWEEN)");
542 println!(" • Subqueries");
543 println!(" • Multi-table operations");
544 println!("\n🎯 Type-safe, compile-time checked, and zero runtime overhead!");
545 println!();
546}Sourcepub fn exists(&self) -> bool
pub fn exists(&self) -> bool
Examples found in repository?
28fn main() {
29 println!("╔════════════════════════════════════════════════════════════╗");
30 println!("║ Query Builder Without Clone - Performance Optimization ║");
31 println!("╚════════════════════════════════════════════════════════════╝\n");
32
33 let employees = vec![
34 Employee {
35 id: 1,
36 name: "Alice".to_string(),
37 email: "alice@example.com".to_string(),
38 department: "Engineering".to_string(),
39 salary: 95000.0,
40 large_data: vec![0; 1000], // Large data - expensive to clone!
41 },
42 Employee {
43 id: 2,
44 name: "Bob".to_string(),
45 email: "bob@example.com".to_string(),
46 department: "Engineering".to_string(),
47 salary: 87000.0,
48 large_data: vec![0; 1000],
49 },
50 Employee {
51 id: 3,
52 name: "Carol".to_string(),
53 email: "carol@example.com".to_string(),
54 department: "Sales".to_string(),
55 salary: 75000.0,
56 large_data: vec![0; 1000],
57 },
58 ];
59
60 let departments = vec![
61 Department {
62 id: 1,
63 name: "Engineering".to_string(),
64 budget: 1000000.0,
65 },
66 Department {
67 id: 2,
68 name: "Sales".to_string(),
69 budget: 500000.0,
70 },
71 ];
72
73 println!("✅ Operations that DON'T require Clone:\n");
74
75 // 1. WHERE filtering - returns Vec<&T>
76 println!("1. WHERE filtering (returns references)");
77 let query = Query::new(&employees)
78 .where_(Employee::department_r(), |dept| dept == "Engineering");
79 let engineering = query.all();
80 println!(" Found {} engineering employees", engineering.len());
81 for emp in &engineering {
82 println!(" - {}: ${:.0}", emp.name, emp.salary);
83 }
84
85 // 2. COUNT - no cloning needed
86 println!("\n2. COUNT aggregation");
87 let count = Query::new(&employees)
88 .where_(Employee::salary_r(), |&sal| sal > 80000.0)
89 .count();
90 println!(" {} employees earn over $80k", count);
91
92 // 3. SELECT - only clones the selected field
93 println!("\n3. SELECT (only selected fields are cloned)");
94 let names: Vec<String> = Query::new(&employees)
95 .select(Employee::name_r());
96 println!(" Employee names: {:?}", names);
97
98 // 4. FIRST - returns Option<&T>
99 println!("\n4. FIRST (returns reference)");
100 let query = Query::new(&employees)
101 .where_(Employee::salary_r(), |&sal| sal > 90000.0);
102 if let Some(emp) = query.first() {
103 println!(" First high earner: {} (${:.0})", emp.name, emp.salary);
104 }
105
106 // 5. SUM/AVG aggregations - no cloning
107 println!("\n5. Aggregations (SUM/AVG)");
108 let eng_query = Query::new(&employees)
109 .where_(Employee::department_r(), |dept| dept == "Engineering");
110 let total = eng_query.sum(Employee::salary_r());
111 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
112 println!(" Engineering total: ${:.0}", total);
113 println!(" Engineering average: ${:.0}", avg);
114
115 // 6. MIN/MAX - no cloning
116 println!("\n6. MIN/MAX");
117 let min = Query::new(&employees).min_float(Employee::salary_r());
118 let max = Query::new(&employees).max_float(Employee::salary_r());
119 println!(" Salary range: ${:.0} - ${:.0}", min.unwrap(), max.unwrap());
120
121 // 7. LIMIT - returns Vec<&T>
122 println!("\n7. LIMIT (returns references)");
123 let query = Query::new(&employees);
124 let first_two = query.limit(2);
125 println!(" First 2 employees:");
126 for emp in &first_two {
127 println!(" - {}", emp.name);
128 }
129
130 // 8. SKIP/Pagination - returns Vec<&T>
131 println!("\n8. SKIP/Pagination (returns references)");
132 let query = Query::new(&employees);
133 let page_2 = query.skip(2).limit(1);
134 println!(" Page 2:");
135 for emp in &page_2 {
136 println!(" - {}", emp.name);
137 }
138
139 // 9. EXISTS - just checks
140 println!("\n9. EXISTS check");
141 let has_sales = Query::new(&employees)
142 .where_(Employee::department_r(), |dept| dept == "Sales")
143 .exists();
144 println!(" Has Sales employees: {}", has_sales);
145
146 // 10. JOIN - no Clone required on L or R!
147 println!("\n10. JOIN operations (no Clone required!)");
148 let results = JoinQuery::new(&employees, &departments)
149 .inner_join(
150 Employee::department_r(),
151 Department::name_r(),
152 |emp, dept| {
153 // Mapper only clones what it needs for the result
154 (emp.name.clone(), dept.budget)
155 },
156 );
157 println!(" Employee-Department pairs:");
158 for (name, budget) in &results {
159 println!(" - {} works in dept with ${:.0} budget", name, budget);
160 }
161
162 println!("\n╔════════════════════════════════════════════════════════════╗");
163 println!("║ Operations that REQUIRE Clone (only when needed) ║");
164 println!("╚════════════════════════════════════════════════════════════╝\n");
165
166 println!("⚠️ The following operations require Clone because they return owned Vec<T>:");
167 println!(" - order_by() / order_by_desc()");
168 println!(" - order_by_float() / order_by_float_desc()");
169 println!(" - group_by()");
170 println!("\n To use these, add #[derive(Clone)] to your struct:");
171 println!(" ```rust");
172 println!(" #[derive(Clone, Keypaths)] // Add Clone here");
173 println!(" struct Employee {{ ... }}");
174 println!(" ```");
175
176 println!("\n╔════════════════════════════════════════════════════════════╗");
177 println!("║ Performance Benefits ║");
178 println!("╚════════════════════════════════════════════════════════════╝\n");
179
180 println!("✅ Zero cloning for most operations");
181 println!("✅ Work with large structs efficiently");
182 println!("✅ No unnecessary memory allocations");
183 println!("✅ Only clone when you actually need owned data");
184 println!("✅ Pay for what you use");
185
186 println!("\n✓ Example complete! Most operations work without Clone.\n");
187}More examples
110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}Sourcepub fn where_after_systemtime(
self,
path: KeyPaths<T, SystemTime>,
reference: SystemTime,
) -> Query<'a, T>
pub fn where_after_systemtime( self, path: KeyPaths<T, SystemTime>, reference: SystemTime, ) -> Query<'a, T>
Sourcepub fn where_before_systemtime(
self,
path: KeyPaths<T, SystemTime>,
reference: SystemTime,
) -> Query<'a, T>
pub fn where_before_systemtime( self, path: KeyPaths<T, SystemTime>, reference: SystemTime, ) -> Query<'a, T>
Sourcepub fn where_between_systemtime(
self,
path: KeyPaths<T, SystemTime>,
start: SystemTime,
end: SystemTime,
) -> Query<'a, T>
pub fn where_between_systemtime( self, path: KeyPaths<T, SystemTime>, start: SystemTime, end: SystemTime, ) -> Query<'a, T>
Source§impl<'a, T> Query<'a, T>where
T: 'static + Clone,
impl<'a, T> Query<'a, T>where
T: 'static + Clone,
Sourcepub fn order_by<F>(&self, path: KeyPaths<T, F>) -> Vec<T>
pub fn order_by<F>(&self, path: KeyPaths<T, F>) -> Vec<T>
Orders results by a field in ascending order.
Note: This method requires T: Clone as it creates owned sorted copies.
§Arguments
path- The key-path to the field to order by
§Example
let sorted = query.order_by(Product::name_r());Examples found in repository?
110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}More examples
33fn main() {
34 let employees = create_test_data();
35
36 println!("\n╔════════════════════════════════════════════════════════════════╗");
37 println!("║ SQL Equivalence Verification Tests ║");
38 println!("╚════════════════════════════════════════════════════════════════╝\n");
39
40 // TEST 1: ORDER BY maintains exact SQL ordering (DESC)
41 println!("Test 1: ORDER BY DESC - Exact ordering");
42 println!("SQL: SELECT * FROM employees ORDER BY salary DESC;");
43
44 let ordered = Query::new(&employees).order_by_float_desc(Employee::salary_r());
45 let expected_order = vec![105000.0, 95000.0, 87000.0, 82000.0, 75000.0, 71000.0];
46 let actual_order: Vec<f64> = ordered.iter().map(|e| e.salary).collect();
47
48 let test1_pass = expected_order == actual_order;
49 print_test("ORDER BY salary DESC produces correct order", test1_pass);
50 if !test1_pass {
51 println!(" Expected: {:?}", expected_order);
52 println!(" Got: {:?}", actual_order);
53 }
54
55 // TEST 2: ORDER BY maintains exact SQL ordering (ASC)
56 println!("\nTest 2: ORDER BY ASC - Exact ordering");
57 println!("SQL: SELECT * FROM employees ORDER BY salary ASC;");
58
59 let ordered_asc = Query::new(&employees).order_by_float(Employee::salary_r());
60 let expected_asc = vec![71000.0, 75000.0, 82000.0, 87000.0, 95000.0, 105000.0];
61 let actual_asc: Vec<f64> = ordered_asc.iter().map(|e| e.salary).collect();
62
63 let test2_pass = expected_asc == actual_asc;
64 print_test("ORDER BY salary ASC produces correct order", test2_pass);
65 if !test2_pass {
66 println!(" Expected: {:?}", expected_asc);
67 println!(" Got: {:?}", actual_asc);
68 }
69
70 // TEST 3: String ordering (alphabetical)
71 println!("\nTest 3: ORDER BY name (alphabetical)");
72 println!("SQL: SELECT name FROM employees ORDER BY name;");
73
74 let ordered_names = Query::new(&employees).order_by(Employee::name_r());
75 let expected_names = vec!["Alice Cooper", "Alice Johnson", "Bob Smith", "Carol White", "David Brown", "Eve Davis"];
76 let actual_names: Vec<&str> = ordered_names.iter().map(|e| e.name.as_str()).collect();
77
78 let test3_pass = expected_names == actual_names;
79 print_test("ORDER BY name produces correct alphabetical order", test3_pass);
80 if !test3_pass {
81 println!(" Expected: {:?}", expected_names);
82 println!(" Got: {:?}", actual_names);
83 }
84
85 // TEST 4: LIKE equivalent - starts with
86 println!("\nTest 4: LIKE 'Alice%' equivalent");
87 println!("SQL: SELECT * FROM employees WHERE name LIKE 'Alice%';");
88
89 let like_alice_query = Query::new(&employees)
90 .where_(Employee::name_r(), |name| name.starts_with("Alice"));
91 let like_alice = like_alice_query.all();
92
93 let test4_pass = like_alice.len() == 2
94 && like_alice.iter().all(|e| e.name.starts_with("Alice"));
95 print_test("LIKE 'Alice%' (starts_with) works correctly", test4_pass);
96 if test4_pass {
97 for emp in &like_alice {
98 println!(" Found: {}", emp.name);
99 }
100 }
101
102 // TEST 5: LIKE equivalent - ends with
103 println!("\nTest 5: LIKE '%son' equivalent");
104 println!("SQL: SELECT * FROM employees WHERE name LIKE '%son';");
105
106 let like_son_query = Query::new(&employees)
107 .where_(Employee::name_r(), |name| name.ends_with("son"));
108 let like_son = like_son_query.all();
109
110 let test5_pass = like_son.len() == 1 && like_son[0].name == "Alice Johnson";
111 print_test("LIKE '%son' (ends_with) works correctly", test5_pass);
112 if test5_pass {
113 for emp in &like_son {
114 println!(" Found: {}", emp.name);
115 }
116 }
117
118 // TEST 6: LIKE equivalent - contains
119 println!("\nTest 6: LIKE '%mit%' equivalent");
120 println!("SQL: SELECT * FROM employees WHERE name LIKE '%mit%';");
121
122 let like_mit_query = Query::new(&employees)
123 .where_(Employee::name_r(), |name| name.contains("mit"));
124 let like_mit = like_mit_query.all();
125
126 let test6_pass = like_mit.len() == 1 && like_mit[0].name == "Bob Smith";
127 print_test("LIKE '%mit%' (contains) works correctly", test6_pass);
128 if test6_pass {
129 for emp in &like_mit {
130 println!(" Found: {}", emp.name);
131 }
132 }
133
134 // TEST 7: IN clause equivalent
135 println!("\nTest 7: IN clause equivalent");
136 println!("SQL: SELECT * FROM employees WHERE department IN ('Engineering', 'Sales');");
137
138 let in_depts_query = Query::new(&employees)
139 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales");
140 let in_depts = in_depts_query.all();
141
142 let test7_pass = in_depts.len() == 5 // 3 Engineering + 2 Sales
143 && in_depts.iter().all(|e| e.department == "Engineering" || e.department == "Sales");
144 print_test("IN clause works correctly", test7_pass);
145 println!(" Found {} employees in Engineering or Sales", in_depts.len());
146
147 // TEST 8: BETWEEN equivalent
148 println!("\nTest 8: BETWEEN clause equivalent");
149 println!("SQL: SELECT * FROM employees WHERE salary BETWEEN 75000 AND 90000;");
150
151 let between_query = Query::new(&employees)
152 .where_(Employee::salary_r(), |&sal| sal >= 75000.0 && sal <= 90000.0);
153 let between = between_query.all();
154
155 let test8_pass = between.len() == 3;
156 print_test("BETWEEN clause works correctly", test8_pass);
157 println!(" Found {} employees with salary between 75K-90K", between.len());
158
159 // TEST 9: COUNT with WHERE
160 println!("\nTest 9: COUNT with WHERE");
161 println!("SQL: SELECT COUNT(*) FROM employees WHERE department = 'Engineering';");
162
163 let count_eng = Query::new(&employees)
164 .where_(Employee::department_r(), |dept| dept == "Engineering")
165 .count();
166
167 let test9_pass = count_eng == 3;
168 print_test("COUNT with WHERE produces correct result", test9_pass);
169 println!(" Count: {} (expected 3)", count_eng);
170
171 // TEST 10: AVG produces exact result
172 println!("\nTest 10: AVG aggregation accuracy");
173 println!("SQL: SELECT AVG(salary) FROM employees WHERE department = 'Engineering';");
174
175 let avg_sal = Query::new(&employees)
176 .where_(Employee::department_r(), |dept| dept == "Engineering")
177 .avg(Employee::salary_r())
178 .unwrap_or(0.0);
179
180 let expected_avg = (95000.0 + 87000.0 + 105000.0) / 3.0;
181 let test10_pass = (avg_sal - expected_avg).abs() < 0.01;
182 print_test("AVG produces mathematically correct result", test10_pass);
183 println!(" Average: ${:.2} (expected ${:.2})", avg_sal, expected_avg);
184
185 // TEST 11: MIN and MAX
186 println!("\nTest 11: MIN and MAX aggregations");
187 println!("SQL: SELECT MIN(salary), MAX(salary) FROM employees;");
188
189 let min_sal = Query::new(&employees).min_float(Employee::salary_r()).unwrap_or(0.0);
190 let max_sal = Query::new(&employees).max_float(Employee::salary_r()).unwrap_or(0.0);
191
192 let test11_pass = min_sal == 71000.0 && max_sal == 105000.0;
193 print_test("MIN and MAX produce correct results", test11_pass);
194 println!(" MIN: ${:.2}, MAX: ${:.2}", min_sal, max_sal);
195
196 // TEST 12: Complex WHERE with AND/OR
197 println!("\nTest 12: Complex WHERE (AND + OR)");
198 println!("SQL: SELECT * FROM employees WHERE (department = 'Engineering' OR department = 'Sales') AND salary > 80000;");
199
200 let complex_query = Query::new(&employees)
201 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
202 .where_(Employee::salary_r(), |&sal| sal > 80000.0);
203 let complex = complex_query.all();
204
205 let test12_pass = complex.len() == 4; // Alice J ($95k), Bob ($87k), David ($82k), Alice C ($105k)
206 print_test("Complex WHERE clause works correctly", test12_pass);
207 println!(" Found {} employees", complex.len());
208
209 // TEST 13: Case-sensitive string comparison (SQL default)
210 println!("\nTest 13: Case-sensitive comparison (like SQL)");
211 println!("SQL: SELECT * FROM employees WHERE department = 'engineering'; -- should find 0");
212
213 let case_sensitive = Query::new(&employees)
214 .where_(Employee::department_r(), |dept| dept == "engineering") // lowercase
215 .count();
216
217 let test13_pass = case_sensitive == 0;
218 print_test("Case-sensitive comparison (SQL default)", test13_pass);
219 println!(" Found {} with lowercase 'engineering' (expected 0)", case_sensitive);
220
221 // TEST 14: Case-insensitive LIKE equivalent
222 println!("\nTest 14: Case-insensitive LIKE (ILIKE equivalent)");
223 println!("SQL: SELECT * FROM employees WHERE LOWER(name) LIKE '%alice%';");
224
225 let ilike_query = Query::new(&employees)
226 .where_(Employee::name_r(), |name| name.to_lowercase().contains("alice"));
227 let ilike = ilike_query.all();
228
229 let test14_pass = ilike.len() == 2;
230 print_test("Case-insensitive LIKE works correctly", test14_pass);
231 println!(" Found {} employees with 'alice' (case-insensitive)", ilike.len());
232
233 // TEST 15: LIMIT produces exact subset
234 println!("\nTest 15: LIMIT clause");
235 println!("SQL: SELECT * FROM employees ORDER BY salary DESC LIMIT 3;");
236
237 let limited = Query::new(&employees)
238 .order_by_float_desc(Employee::salary_r())
239 .into_iter()
240 .take(3)
241 .collect::<Vec<_>>();
242
243 let test15_pass = limited.len() == 3
244 && limited[0].salary == 105000.0
245 && limited[1].salary == 95000.0
246 && limited[2].salary == 87000.0;
247 print_test("LIMIT returns correct top-N results", test15_pass);
248 println!(" Top 3 salaries: ${:.0}, ${:.0}, ${:.0}",
249 limited[0].salary, limited[1].salary, limited[2].salary);
250
251 // TEST 16: GROUP BY produces correct groups
252 println!("\nTest 16: GROUP BY");
253 println!("SQL: SELECT department, COUNT(*) FROM employees GROUP BY department;");
254
255 let grouped = Query::new(&employees).group_by(Employee::department_r());
256 let eng_count = grouped.get("Engineering").map(|v| v.len()).unwrap_or(0);
257 let sales_count = grouped.get("Sales").map(|v| v.len()).unwrap_or(0);
258 let marketing_count = grouped.get("Marketing").map(|v| v.len()).unwrap_or(0);
259
260 let test16_pass = eng_count == 3 && sales_count == 2 && marketing_count == 1;
261 print_test("GROUP BY produces correct counts", test16_pass);
262 println!(" Engineering: {}, Sales: {}, Marketing: {}", eng_count, sales_count, marketing_count);
263
264 // TEST 17: Email pattern matching (regex-like)
265 println!("\nTest 17: Email domain filtering (LIKE '%@example.com')");
266 println!("SQL: SELECT * FROM employees WHERE email LIKE '%@example.com';");
267
268 let example_emails = Query::new(&employees)
269 .where_(Employee::email_r(), |email| email.ends_with("@example.com"))
270 .count();
271
272 let test17_pass = example_emails == 6; // All employees have @example.com emails
273 print_test("Email pattern matching works correctly", test17_pass);
274 println!(" Found {} employees with @example.com emails", example_emails);
275
276 // Summary
277 println!("\n╔════════════════════════════════════════════════════════════════╗");
278 println!("║ Test Summary ║");
279 println!("╚════════════════════════════════════════════════════════════════╝\n");
280
281 let tests = vec![
282 ("ORDER BY DESC", test1_pass),
283 ("ORDER BY ASC", test2_pass),
284 ("ORDER BY name", test3_pass),
285 ("LIKE 'prefix%'", test4_pass),
286 ("LIKE '%suffix'", test5_pass),
287 ("LIKE '%contains%'", test6_pass),
288 ("IN clause", test7_pass),
289 ("BETWEEN clause", test8_pass),
290 ("COUNT", test9_pass),
291 ("AVG accuracy", test10_pass),
292 ("MIN/MAX", test11_pass),
293 ("Complex WHERE", test12_pass),
294 ("Case-sensitive", test13_pass),
295 ("Case-insensitive", test14_pass),
296 ("LIMIT", test15_pass),
297 ("GROUP BY", test16_pass),
298 ("Email patterns", test17_pass),
299 ];
300
301 let passed = tests.iter().filter(|(_, p)| *p).count();
302 let total = tests.len();
303
304 println!("Results: {}/{} tests passed", passed, total);
305
306 if passed == total {
307 println!("\n🎉 All tests PASSED! Rust Query Builder produces exact SQL-equivalent results!");
308 println!("\n✅ Verified:");
309 println!(" • Exact ordering (ASC/DESC)");
310 println!(" • LIKE operations (starts_with, ends_with, contains)");
311 println!(" • IN clause (OR conditions)");
312 println!(" • BETWEEN clause");
313 println!(" • Aggregations (COUNT, AVG, MIN, MAX)");
314 println!(" • Complex WHERE conditions");
315 println!(" • Case sensitivity");
316 println!(" • LIMIT clause");
317 println!(" • GROUP BY");
318 println!(" • Pattern matching");
319 } else {
320 println!("\n⚠️ {} test(s) failed. See details above.", total - passed);
321 }
322}84fn main() {
85 let employees = create_employees();
86 let departments = create_departments();
87 let projects = create_projects();
88
89 println!("\n╔════════════════════════════════════════════════════════════════════════╗");
90 println!("║ SQL vs Rust Query Builder Comparison ║");
91 println!("║ Demonstrating equivalent operations ║");
92 println!("╚════════════════════════════════════════════════════════════════════════╝");
93
94 // ============================================================================
95 // EXAMPLE 1: Simple SELECT with WHERE
96 // ============================================================================
97 print_separator("Example 1: SELECT with WHERE clause");
98 print_query(
99 "SELECT * FROM employees WHERE department = 'Engineering';",
100 "Filter employees by department"
101 );
102
103 let eng_query = Query::new(&employees)
104 .where_(Employee::department_r(), |dept| dept == "Engineering");
105 let engineering_employees = eng_query.all();
106
107 for emp in &engineering_employees {
108 println!(" ID: {}, Name: {}, Salary: ${:.2}", emp.id, emp.name, emp.salary);
109 }
110 println!("\nRust Query Builder:");
111 println!("Query::new(&employees)");
112 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\")");
113 println!(" .all()");
114 println!("✓ Found {} employees", engineering_employees.len());
115
116 // ============================================================================
117 // EXAMPLE 2: SELECT specific columns
118 // ============================================================================
119 print_separator("Example 2: SELECT specific columns (Projection)");
120 print_query(
121 "SELECT name FROM employees WHERE salary > 80000;",
122 "Get names of high-earning employees"
123 );
124
125 let high_earners = Query::new(&employees)
126 .where_(Employee::salary_r(), |&salary| salary > 80000.0)
127 .select(Employee::name_r());
128
129 for name in &high_earners {
130 println!(" {}", name);
131 }
132 println!("\nRust Query Builder:");
133 println!("Query::new(&employees)");
134 println!(" .where_(Employee::salary_r(), |&salary| salary > 80000.0)");
135 println!(" .select(Employee::name_r())");
136 println!("✓ Found {} employees", high_earners.len());
137
138 // ============================================================================
139 // EXAMPLE 3: COUNT
140 // ============================================================================
141 print_separator("Example 3: COUNT aggregation");
142 print_query(
143 "SELECT COUNT(*) FROM employees WHERE age < 30;",
144 "Count young employees"
145 );
146
147 let young_count = Query::new(&employees)
148 .where_(Employee::age_r(), |&age| age < 30)
149 .count();
150
151 println!(" Count: {}", young_count);
152 println!("\nRust Query Builder:");
153 println!("Query::new(&employees)");
154 println!(" .where_(Employee::age_r(), |&age| age < 30)");
155 println!(" .count()");
156 println!("✓ Result: {}", young_count);
157
158 // ============================================================================
159 // EXAMPLE 4: SUM, AVG, MIN, MAX
160 // ============================================================================
161 print_separator("Example 4: Aggregate functions (SUM, AVG, MIN, MAX)");
162 print_query(
163 "SELECT \n\
164 SUM(salary) as total_salary,\n\
165 AVG(salary) as avg_salary,\n\
166 MIN(salary) as min_salary,\n\
167 MAX(salary) as max_salary\n\
168 FROM employees WHERE department = 'Engineering';",
169 "Engineering department salary statistics"
170 );
171
172 let eng_query = Query::new(&employees)
173 .where_(Employee::department_r(), |dept| dept == "Engineering");
174
175 let total = eng_query.sum(Employee::salary_r());
176 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
177 let min = eng_query.min_float(Employee::salary_r()).unwrap_or(0.0);
178 let max = eng_query.max_float(Employee::salary_r()).unwrap_or(0.0);
179
180 println!(" Total Salary: ${:.2}", total);
181 println!(" Avg Salary: ${:.2}", avg);
182 println!(" Min Salary: ${:.2}", min);
183 println!(" Max Salary: ${:.2}", max);
184
185 println!("\nRust Query Builder:");
186 println!("let query = Query::new(&employees)");
187 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\");");
188 println!("query.sum(Employee::salary_r()) // ${:.2}", total);
189 println!("query.avg(Employee::salary_r()) // ${:.2}", avg);
190 println!("query.min_float(Employee::salary_r()) // ${:.2}", min);
191 println!("query.max_float(Employee::salary_r()) // ${:.2}", max);
192
193 // ============================================================================
194 // EXAMPLE 5: GROUP BY with aggregation
195 // ============================================================================
196 print_separator("Example 5: GROUP BY with aggregation");
197 print_query(
198 "SELECT \n\
199 department,\n\
200 COUNT(*) as emp_count,\n\
201 AVG(salary) as avg_salary\n\
202 FROM employees\n\
203 GROUP BY department;",
204 "Statistics by department"
205 );
206
207 let by_dept = Query::new(&employees).group_by(Employee::department_r());
208
209 for (dept, emps) in &by_dept {
210 let dept_query = Query::new(emps);
211 let count = emps.len();
212 let avg_sal = dept_query.avg(Employee::salary_r()).unwrap_or(0.0);
213 println!(" {}: {} employees, avg salary ${:.2}", dept, count, avg_sal);
214 }
215
216 println!("\nRust Query Builder:");
217 println!("let by_dept = Query::new(&employees).group_by(Employee::department_r());");
218 println!("for (dept, emps) in &by_dept {{");
219 println!(" let dept_query = Query::new(emps);");
220 println!(" dept_query.avg(Employee::salary_r())");
221 println!("}}");
222
223 // ============================================================================
224 // EXAMPLE 6: ORDER BY
225 // ============================================================================
226 print_separator("Example 6: ORDER BY");
227 print_query(
228 "SELECT name, salary FROM employees\n\
229 WHERE department = 'Sales'\n\
230 ORDER BY salary DESC;",
231 "Sales employees ordered by salary (descending)"
232 );
233
234 let sales_sorted = Query::new(&employees)
235 .where_(Employee::department_r(), |dept| dept == "Sales")
236 .order_by_float_desc(Employee::salary_r());
237
238 for emp in &sales_sorted {
239 println!(" {}: ${:.2}", emp.name, emp.salary);
240 }
241
242 println!("\nRust Query Builder:");
243 println!("Query::new(&employees)");
244 println!(" .where_(Employee::department_r(), |dept| dept == \"Sales\")");
245 println!(" .order_by_float_desc(Employee::salary_r())");
246
247 // ============================================================================
248 // EXAMPLE 7: Multiple WHERE conditions (AND)
249 // ============================================================================
250 print_separator("Example 7: Multiple WHERE conditions (AND)");
251 print_query(
252 "SELECT * FROM employees\n\
253 WHERE salary > 70000 AND age < 35;",
254 "High-earning young employees"
255 );
256
257 let filter_query = Query::new(&employees)
258 .where_(Employee::salary_r(), |&salary| salary > 70000.0)
259 .where_(Employee::age_r(), |&age| age < 35);
260 let filtered = filter_query.all();
261
262 for emp in &filtered {
263 println!(" {}: Age {}, Salary ${:.2}", emp.name, emp.age, emp.salary);
264 }
265
266 println!("\nRust Query Builder:");
267 println!("Query::new(&employees)");
268 println!(" .where_(Employee::salary_r(), |&salary| salary > 70000.0)");
269 println!(" .where_(Employee::age_r(), |&age| age < 35)");
270 println!(" .all()");
271 println!("✓ Found {} employees", filtered.len());
272
273 // ============================================================================
274 // EXAMPLE 8: LIMIT (TOP N)
275 // ============================================================================
276 print_separator("Example 8: LIMIT / TOP N");
277 print_query(
278 "SELECT TOP 3 name, salary FROM employees\n\
279 ORDER BY salary DESC;",
280 "Top 3 highest paid employees"
281 );
282
283 let top_earners = Query::new(&employees)
284 .order_by_float_desc(Employee::salary_r());
285
286 for (i, emp) in top_earners.iter().take(3).enumerate() {
287 println!(" {}. {}: ${:.2}", i + 1, emp.name, emp.salary);
288 }
289
290 println!("\nRust Query Builder:");
291 println!("Query::new(&employees)");
292 println!(" .order_by_float_desc(Employee::salary_r())");
293 println!(" .into_iter().take(3)");
294
295 // ============================================================================
296 // EXAMPLE 9: OFFSET and LIMIT (Pagination)
297 // ============================================================================
298 print_separator("Example 9: OFFSET and LIMIT (Pagination)");
299 print_query(
300 "SELECT name FROM employees\n\
301 ORDER BY name\n\
302 LIMIT 3 OFFSET 3;",
303 "Page 2 of employee names (3 per page)"
304 );
305
306 let page_2 = Query::new(&employees)
307 .order_by(Employee::name_r())
308 .into_iter()
309 .skip(3)
310 .take(3)
311 .collect::<Vec<_>>();
312
313 for emp in &page_2 {
314 println!(" {}", emp.name);
315 }
316
317 println!("\nRust Query Builder:");
318 println!("Query::new(&employees)");
319 println!(" .order_by(Employee::name_r())");
320 println!(" .into_iter().skip(3).take(3)");
321
322 // ============================================================================
323 // EXAMPLE 10: INNER JOIN
324 // ============================================================================
325 print_separator("Example 10: INNER JOIN");
326 print_query(
327 "SELECT e.name, d.name as dept_name, d.budget\n\
328 FROM employees e\n\
329 INNER JOIN departments d ON e.department = d.name;",
330 "Employees with their department info"
331 );
332
333 let emp_dept = JoinQuery::new(&employees, &departments).inner_join(
334 Employee::department_r(),
335 Department::name_r(),
336 |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget),
337 );
338
339 for (emp_name, dept_name, budget) in emp_dept.iter().take(5) {
340 println!(" {} works in {} (Budget: ${:.0})", emp_name, dept_name, budget);
341 }
342 println!(" ... (showing first 5)");
343
344 println!("\nRust Query Builder:");
345 println!("JoinQuery::new(&employees, &departments).inner_join(");
346 println!(" Employee::department_r(),");
347 println!(" Department::name_r(),");
348 println!(" |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget)");
349 println!(")");
350 println!("✓ Found {} matches", emp_dept.len());
351
352 // ============================================================================
353 // EXAMPLE 11: GROUP BY with HAVING equivalent
354 // ============================================================================
355 print_separator("Example 11: GROUP BY with filtering (HAVING equivalent)");
356 print_query(
357 "SELECT city, COUNT(*) as emp_count, AVG(salary) as avg_salary\n\
358 FROM employees\n\
359 GROUP BY city\n\
360 HAVING COUNT(*) > 1;",
361 "Cities with multiple employees"
362 );
363
364 let by_city = Query::new(&employees).group_by(Employee::city_r());
365 let mut city_stats: Vec<_> = by_city
366 .iter()
367 .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent
368 .map(|(city, emps)| {
369 let avg_sal = Query::new(emps).avg(Employee::salary_r()).unwrap_or(0.0);
370 (city.clone(), emps.len(), avg_sal)
371 })
372 .collect();
373
374 city_stats.sort_by(|a, b| b.1.cmp(&a.1)); // Sort by count
375
376 for (city, count, avg_sal) in &city_stats {
377 println!(" {}: {} employees, avg salary ${:.2}", city, count, avg_sal);
378 }
379
380 println!("\nRust Query Builder:");
381 println!("let by_city = Query::new(&employees).group_by(Employee::city_r());");
382 println!("by_city.iter()");
383 println!(" .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent");
384 println!(" .map(|(city, emps)| {{");
385 println!(" let avg = Query::new(emps).avg(Employee::salary_r());");
386 println!(" (city, emps.len(), avg)");
387 println!(" }})");
388
389 // ============================================================================
390 // EXAMPLE 12: Complex query with multiple operations
391 // ============================================================================
392 print_separator("Example 12: Complex multi-operation query");
393 print_query(
394 "SELECT name, salary, age\n\
395 FROM employees\n\
396 WHERE department IN ('Engineering', 'Sales')\n\
397 AND salary BETWEEN 80000 AND 100000\n\
398 AND age >= 30\n\
399 ORDER BY salary DESC;",
400 "Experienced mid-to-senior level employees in core departments"
401 );
402
403 let complex_query = Query::new(&employees)
404 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
405 .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)
406 .where_(Employee::age_r(), |&age| age >= 30)
407 .order_by_float_desc(Employee::salary_r());
408
409 for emp in &complex_query {
410 println!(" {}: Age {}, {} dept, ${:.2}", emp.name, emp.age, emp.department, emp.salary);
411 }
412
413 println!("\nRust Query Builder:");
414 println!("Query::new(&employees)");
415 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\" || dept == \"Sales\")");
416 println!(" .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)");
417 println!(" .where_(Employee::age_r(), |&age| age >= 30)");
418 println!(" .order_by_float_desc(Employee::salary_r())");
419 println!("✓ Found {} employees", complex_query.len());
420
421 // ============================================================================
422 // EXAMPLE 13: Three-table JOIN
423 // ============================================================================
424 print_separator("Example 13: Three-table JOIN");
425 print_query(
426 "SELECT p.name as project, d.name as department, d.location\n\
427 FROM projects p\n\
428 INNER JOIN departments d ON p.department_id = d.id;",
429 "Projects with their department details"
430 );
431
432 let proj_dept = JoinQuery::new(&projects, &departments).inner_join(
433 Project::department_id_r(),
434 Department::id_r(),
435 |proj, dept| {
436 (proj.name.clone(), dept.name.clone(), dept.location.clone(), proj.budget)
437 },
438 );
439
440 for (proj_name, dept_name, location, budget) in &proj_dept {
441 println!(" {}: {} dept in {} (${:.0})", proj_name, dept_name, location, budget);
442 }
443
444 println!("\nRust Query Builder:");
445 println!("JoinQuery::new(&projects, &departments).inner_join(");
446 println!(" Project::department_id_r(),");
447 println!(" Department::id_r(),");
448 println!(" |proj, dept| (proj.name, dept.name, dept.location, proj.budget)");
449 println!(")");
450
451 // ============================================================================
452 // EXAMPLE 14: Subquery equivalent (using intermediate results)
453 // ============================================================================
454 print_separator("Example 14: Subquery equivalent");
455 print_query(
456 "SELECT * FROM employees\n\
457 WHERE salary > (SELECT AVG(salary) FROM employees);",
458 "Employees earning above average"
459 );
460
461 let avg_salary = Query::new(&employees)
462 .avg(Employee::salary_r())
463 .unwrap_or(0.0);
464
465 let above_avg_query = Query::new(&employees)
466 .where_(Employee::salary_r(), move |&sal| sal > avg_salary);
467 let above_avg = above_avg_query.all();
468
469 println!(" Average salary: ${:.2}", avg_salary);
470 for emp in &above_avg {
471 println!(" {}: ${:.2} ({:.1}% above average)",
472 emp.name, emp.salary, ((emp.salary - avg_salary) / avg_salary * 100.0));
473 }
474
475 println!("\nRust Query Builder:");
476 println!("let avg = Query::new(&employees).avg(Employee::salary_r()).unwrap_or(0.0);");
477 println!("Query::new(&employees)");
478 println!(" .where_(Employee::salary_r(), |&sal| sal > avg)");
479 println!(" .all()");
480 println!("✓ Found {} employees above average", above_avg.len());
481
482 // ============================================================================
483 // EXAMPLE 15: Advanced aggregation (revenue calculation)
484 // ============================================================================
485 print_separator("Example 15: Advanced aggregation");
486 print_query(
487 "SELECT \n\
488 d.name,\n\
489 d.budget as dept_budget,\n\
490 SUM(p.budget) as total_project_budget,\n\
491 (d.budget - SUM(p.budget)) as remaining_budget\n\
492 FROM departments d\n\
493 LEFT JOIN projects p ON d.id = p.department_id\n\
494 GROUP BY d.name, d.budget;",
495 "Department budget utilization"
496 );
497
498 // Join departments with projects
499 let dept_projects = JoinQuery::new(&departments, &projects).left_join(
500 Department::id_r(),
501 Project::department_id_r(),
502 |dept, proj| (dept.clone(), proj.map(|p| p.clone())),
503 );
504
505 // Aggregate by department
506 let mut dept_budget_map: HashMap<String, (f64, Vec<f64>)> = HashMap::new();
507 for (dept, proj) in dept_projects {
508 let entry = dept_budget_map
509 .entry(dept.name.clone())
510 .or_insert((dept.budget, Vec::new()));
511 if let Some(p) = proj {
512 entry.1.push(p.budget);
513 }
514 }
515
516 for (dept_name, (total_budget, project_budgets)) in dept_budget_map.iter() {
517 let used: f64 = project_budgets.iter().sum();
518 let remaining = total_budget - used;
519 println!(" {}: Budget ${:.0}, Used ${:.0}, Remaining ${:.0} ({:.1}% utilized)",
520 dept_name, total_budget, used, remaining, (used / total_budget * 100.0));
521 }
522
523 println!("\nRust Query Builder:");
524 println!("let dept_projects = JoinQuery::new(&departments, &projects)");
525 println!(" .left_join(Department::id_r(), Project::department_id_r(), ...)");
526 println!("// Then aggregate using HashMap");
527
528 // ============================================================================
529 // Summary
530 // ============================================================================
531 print_separator("Summary");
532 println!("\n✓ All 15 SQL queries successfully replicated with Rust Query Builder!");
533 println!("\nDemonstrated equivalents for:");
534 println!(" • SELECT with WHERE");
535 println!(" • Projection (SELECT specific columns)");
536 println!(" • Aggregations (COUNT, SUM, AVG, MIN, MAX)");
537 println!(" • GROUP BY");
538 println!(" • ORDER BY");
539 println!(" • LIMIT and OFFSET");
540 println!(" • INNER JOIN and LEFT JOIN");
541 println!(" • Complex conditions (AND, OR, BETWEEN)");
542 println!(" • Subqueries");
543 println!(" • Multi-table operations");
544 println!("\n🎯 Type-safe, compile-time checked, and zero runtime overhead!");
545 println!();
546}Sourcepub fn order_by_desc<F>(&self, path: KeyPaths<T, F>) -> Vec<T>
pub fn order_by_desc<F>(&self, path: KeyPaths<T, F>) -> Vec<T>
Sourcepub fn order_by_float(&self, path: KeyPaths<T, f64>) -> Vec<T>
pub fn order_by_float(&self, path: KeyPaths<T, f64>) -> Vec<T>
Orders results by a float field in ascending order.
Note: This method requires T: Clone as it creates owned sorted copies.
§Arguments
path- The key-path to the f64 field to order by
§Example
let sorted = query.order_by_float(Product::price_r());Examples found in repository?
30fn main() {
31 println!("Testing documentation examples...\n");
32
33 // Example from README - Quick Start
34 println!("Test 1: README Quick Start Example");
35 {
36 let products = vec![
37 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
38 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
39 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
40 ];
41
42 let affordable_query = Query::new(&products)
43 .where_(Product::category_r(), |cat| cat == "Electronics")
44 .where_(Product::price_r(), |&price| price < 100.0);
45 let affordable_electronics = affordable_query.all();
46
47 println!(" Found {} affordable electronics ✅", affordable_electronics.len());
48 }
49
50 // Example from README - Filtering
51 println!("\nTest 2: Filtering Example");
52 {
53 let products = vec![
54 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
55 ];
56
57 let electronics_query = Query::new(&products)
58 .where_(Product::category_r(), |cat| cat == "Electronics");
59 let electronics = electronics_query.all();
60
61 println!(" Found {} electronics ✅", electronics.len());
62 }
63
64 // Example from README - Selecting
65 println!("\nTest 3: Selecting Fields Example");
66 {
67 let products = vec![
68 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
69 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
70 ];
71
72 let names: Vec<String> = Query::new(&products)
73 .select(Product::name_r());
74
75 println!(" Selected {} names ✅", names.len());
76 }
77
78 // Example from README - Ordering
79 println!("\nTest 4: Ordering Example");
80 {
81 let products = vec![
82 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
83 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
84 ];
85
86 let by_price = Query::new(&products).order_by_float(Product::price_r());
87 println!(" Ordered {} products ✅", by_price.len());
88 }
89
90 // Example from README - Aggregations
91 println!("\nTest 5: Aggregations Example");
92 {
93 let products = vec![
94 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
95 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
96 ];
97
98 let electronics_query = Query::new(&products)
99 .where_(Product::category_r(), |cat| cat == "Electronics");
100
101 let count = electronics_query.count();
102 let total_value: f64 = electronics_query.sum(Product::price_r());
103 let avg_price = electronics_query.avg(Product::price_r()).unwrap_or(0.0);
104
105 println!(" Count: {}, Total: ${:.2}, Avg: ${:.2} ✅", count, total_value, avg_price);
106 }
107
108 // Example from README - Grouping
109 println!("\nTest 6: Grouping Example");
110 {
111 let products = vec![
112 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
113 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
114 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
115 ];
116
117 let by_category = Query::new(&products).group_by(Product::category_r());
118 println!(" Grouped into {} categories ✅", by_category.len());
119 }
120
121 // Example from README - Pagination
122 println!("\nTest 7: Pagination Example");
123 {
124 let products = vec![
125 Product { id: 1, name: "P1".to_string(), price: 10.0, category: "A".to_string(), stock: 1, rating: 4.0 },
126 Product { id: 2, name: "P2".to_string(), price: 20.0, category: "A".to_string(), stock: 1, rating: 4.0 },
127 Product { id: 3, name: "P3".to_string(), price: 30.0, category: "A".to_string(), stock: 1, rating: 4.0 },
128 ];
129
130 let query = Query::new(&products);
131 let first_10 = query.limit(10);
132 let page_1 = query.skip(0).limit(10);
133
134 println!(" Limited to {} products ✅", first_10.len());
135 println!(" Page 1 has {} products ✅", page_1.len());
136 }
137
138 // Example from README - Join
139 println!("\nTest 8: Join Example");
140 {
141 let users = vec![
142 User { id: 1, name: "Alice".to_string() },
143 User { id: 2, name: "Bob".to_string() },
144 ];
145
146 let orders = vec![
147 Order { id: 101, user_id: 1, total: 99.99 },
148 Order { id: 102, user_id: 1, total: 149.99 },
149 ];
150
151 let user_orders = JoinQuery::new(&users, &orders).inner_join(
152 User::id_r(),
153 Order::user_id_r(),
154 |user, order| (user.name.clone(), order.total),
155 );
156
157 println!(" Joined {} user-order pairs ✅", user_orders.len());
158 }
159
160 // Example from SQL_COMPARISON - SELECT with WHERE
161 println!("\nTest 9: SQL Comparison - SELECT with WHERE");
162 {
163 #[derive(Clone, Keypaths)]
164 struct Employee {
165 department: String,
166 }
167
168 let employees = vec![
169 Employee { department: "Engineering".to_string() },
170 Employee { department: "Sales".to_string() },
171 ];
172
173 let engineering_query = Query::new(&employees)
174 .where_(Employee::department_r(), |dept| dept == "Engineering");
175 let engineering = engineering_query.all();
176
177 println!(" Found {} engineering employees ✅", engineering.len());
178 }
179
180 // Example from USAGE.md - Complex Filtering
181 println!("\nTest 10: USAGE - Complex Filtering");
182 {
183 let products = vec![
184 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
185 ];
186
187 let results_query = Query::new(&products)
188 .where_(Product::category_r(), |cat| cat == "Electronics")
189 .where_(Product::price_r(), |&price| price >= 100.0 && price <= 500.0)
190 .where_(Product::stock_r(), |&stock| stock > 10);
191 let results = results_query.order_by_float(Product::price_r());
192
193 println!(" Filtered {} products ✅", results.len());
194 }
195
196 println!("\n✅ All documentation examples compile and run successfully!");
197}More examples
110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}33fn main() {
34 let employees = create_test_data();
35
36 println!("\n╔════════════════════════════════════════════════════════════════╗");
37 println!("║ SQL Equivalence Verification Tests ║");
38 println!("╚════════════════════════════════════════════════════════════════╝\n");
39
40 // TEST 1: ORDER BY maintains exact SQL ordering (DESC)
41 println!("Test 1: ORDER BY DESC - Exact ordering");
42 println!("SQL: SELECT * FROM employees ORDER BY salary DESC;");
43
44 let ordered = Query::new(&employees).order_by_float_desc(Employee::salary_r());
45 let expected_order = vec![105000.0, 95000.0, 87000.0, 82000.0, 75000.0, 71000.0];
46 let actual_order: Vec<f64> = ordered.iter().map(|e| e.salary).collect();
47
48 let test1_pass = expected_order == actual_order;
49 print_test("ORDER BY salary DESC produces correct order", test1_pass);
50 if !test1_pass {
51 println!(" Expected: {:?}", expected_order);
52 println!(" Got: {:?}", actual_order);
53 }
54
55 // TEST 2: ORDER BY maintains exact SQL ordering (ASC)
56 println!("\nTest 2: ORDER BY ASC - Exact ordering");
57 println!("SQL: SELECT * FROM employees ORDER BY salary ASC;");
58
59 let ordered_asc = Query::new(&employees).order_by_float(Employee::salary_r());
60 let expected_asc = vec![71000.0, 75000.0, 82000.0, 87000.0, 95000.0, 105000.0];
61 let actual_asc: Vec<f64> = ordered_asc.iter().map(|e| e.salary).collect();
62
63 let test2_pass = expected_asc == actual_asc;
64 print_test("ORDER BY salary ASC produces correct order", test2_pass);
65 if !test2_pass {
66 println!(" Expected: {:?}", expected_asc);
67 println!(" Got: {:?}", actual_asc);
68 }
69
70 // TEST 3: String ordering (alphabetical)
71 println!("\nTest 3: ORDER BY name (alphabetical)");
72 println!("SQL: SELECT name FROM employees ORDER BY name;");
73
74 let ordered_names = Query::new(&employees).order_by(Employee::name_r());
75 let expected_names = vec!["Alice Cooper", "Alice Johnson", "Bob Smith", "Carol White", "David Brown", "Eve Davis"];
76 let actual_names: Vec<&str> = ordered_names.iter().map(|e| e.name.as_str()).collect();
77
78 let test3_pass = expected_names == actual_names;
79 print_test("ORDER BY name produces correct alphabetical order", test3_pass);
80 if !test3_pass {
81 println!(" Expected: {:?}", expected_names);
82 println!(" Got: {:?}", actual_names);
83 }
84
85 // TEST 4: LIKE equivalent - starts with
86 println!("\nTest 4: LIKE 'Alice%' equivalent");
87 println!("SQL: SELECT * FROM employees WHERE name LIKE 'Alice%';");
88
89 let like_alice_query = Query::new(&employees)
90 .where_(Employee::name_r(), |name| name.starts_with("Alice"));
91 let like_alice = like_alice_query.all();
92
93 let test4_pass = like_alice.len() == 2
94 && like_alice.iter().all(|e| e.name.starts_with("Alice"));
95 print_test("LIKE 'Alice%' (starts_with) works correctly", test4_pass);
96 if test4_pass {
97 for emp in &like_alice {
98 println!(" Found: {}", emp.name);
99 }
100 }
101
102 // TEST 5: LIKE equivalent - ends with
103 println!("\nTest 5: LIKE '%son' equivalent");
104 println!("SQL: SELECT * FROM employees WHERE name LIKE '%son';");
105
106 let like_son_query = Query::new(&employees)
107 .where_(Employee::name_r(), |name| name.ends_with("son"));
108 let like_son = like_son_query.all();
109
110 let test5_pass = like_son.len() == 1 && like_son[0].name == "Alice Johnson";
111 print_test("LIKE '%son' (ends_with) works correctly", test5_pass);
112 if test5_pass {
113 for emp in &like_son {
114 println!(" Found: {}", emp.name);
115 }
116 }
117
118 // TEST 6: LIKE equivalent - contains
119 println!("\nTest 6: LIKE '%mit%' equivalent");
120 println!("SQL: SELECT * FROM employees WHERE name LIKE '%mit%';");
121
122 let like_mit_query = Query::new(&employees)
123 .where_(Employee::name_r(), |name| name.contains("mit"));
124 let like_mit = like_mit_query.all();
125
126 let test6_pass = like_mit.len() == 1 && like_mit[0].name == "Bob Smith";
127 print_test("LIKE '%mit%' (contains) works correctly", test6_pass);
128 if test6_pass {
129 for emp in &like_mit {
130 println!(" Found: {}", emp.name);
131 }
132 }
133
134 // TEST 7: IN clause equivalent
135 println!("\nTest 7: IN clause equivalent");
136 println!("SQL: SELECT * FROM employees WHERE department IN ('Engineering', 'Sales');");
137
138 let in_depts_query = Query::new(&employees)
139 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales");
140 let in_depts = in_depts_query.all();
141
142 let test7_pass = in_depts.len() == 5 // 3 Engineering + 2 Sales
143 && in_depts.iter().all(|e| e.department == "Engineering" || e.department == "Sales");
144 print_test("IN clause works correctly", test7_pass);
145 println!(" Found {} employees in Engineering or Sales", in_depts.len());
146
147 // TEST 8: BETWEEN equivalent
148 println!("\nTest 8: BETWEEN clause equivalent");
149 println!("SQL: SELECT * FROM employees WHERE salary BETWEEN 75000 AND 90000;");
150
151 let between_query = Query::new(&employees)
152 .where_(Employee::salary_r(), |&sal| sal >= 75000.0 && sal <= 90000.0);
153 let between = between_query.all();
154
155 let test8_pass = between.len() == 3;
156 print_test("BETWEEN clause works correctly", test8_pass);
157 println!(" Found {} employees with salary between 75K-90K", between.len());
158
159 // TEST 9: COUNT with WHERE
160 println!("\nTest 9: COUNT with WHERE");
161 println!("SQL: SELECT COUNT(*) FROM employees WHERE department = 'Engineering';");
162
163 let count_eng = Query::new(&employees)
164 .where_(Employee::department_r(), |dept| dept == "Engineering")
165 .count();
166
167 let test9_pass = count_eng == 3;
168 print_test("COUNT with WHERE produces correct result", test9_pass);
169 println!(" Count: {} (expected 3)", count_eng);
170
171 // TEST 10: AVG produces exact result
172 println!("\nTest 10: AVG aggregation accuracy");
173 println!("SQL: SELECT AVG(salary) FROM employees WHERE department = 'Engineering';");
174
175 let avg_sal = Query::new(&employees)
176 .where_(Employee::department_r(), |dept| dept == "Engineering")
177 .avg(Employee::salary_r())
178 .unwrap_or(0.0);
179
180 let expected_avg = (95000.0 + 87000.0 + 105000.0) / 3.0;
181 let test10_pass = (avg_sal - expected_avg).abs() < 0.01;
182 print_test("AVG produces mathematically correct result", test10_pass);
183 println!(" Average: ${:.2} (expected ${:.2})", avg_sal, expected_avg);
184
185 // TEST 11: MIN and MAX
186 println!("\nTest 11: MIN and MAX aggregations");
187 println!("SQL: SELECT MIN(salary), MAX(salary) FROM employees;");
188
189 let min_sal = Query::new(&employees).min_float(Employee::salary_r()).unwrap_or(0.0);
190 let max_sal = Query::new(&employees).max_float(Employee::salary_r()).unwrap_or(0.0);
191
192 let test11_pass = min_sal == 71000.0 && max_sal == 105000.0;
193 print_test("MIN and MAX produce correct results", test11_pass);
194 println!(" MIN: ${:.2}, MAX: ${:.2}", min_sal, max_sal);
195
196 // TEST 12: Complex WHERE with AND/OR
197 println!("\nTest 12: Complex WHERE (AND + OR)");
198 println!("SQL: SELECT * FROM employees WHERE (department = 'Engineering' OR department = 'Sales') AND salary > 80000;");
199
200 let complex_query = Query::new(&employees)
201 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
202 .where_(Employee::salary_r(), |&sal| sal > 80000.0);
203 let complex = complex_query.all();
204
205 let test12_pass = complex.len() == 4; // Alice J ($95k), Bob ($87k), David ($82k), Alice C ($105k)
206 print_test("Complex WHERE clause works correctly", test12_pass);
207 println!(" Found {} employees", complex.len());
208
209 // TEST 13: Case-sensitive string comparison (SQL default)
210 println!("\nTest 13: Case-sensitive comparison (like SQL)");
211 println!("SQL: SELECT * FROM employees WHERE department = 'engineering'; -- should find 0");
212
213 let case_sensitive = Query::new(&employees)
214 .where_(Employee::department_r(), |dept| dept == "engineering") // lowercase
215 .count();
216
217 let test13_pass = case_sensitive == 0;
218 print_test("Case-sensitive comparison (SQL default)", test13_pass);
219 println!(" Found {} with lowercase 'engineering' (expected 0)", case_sensitive);
220
221 // TEST 14: Case-insensitive LIKE equivalent
222 println!("\nTest 14: Case-insensitive LIKE (ILIKE equivalent)");
223 println!("SQL: SELECT * FROM employees WHERE LOWER(name) LIKE '%alice%';");
224
225 let ilike_query = Query::new(&employees)
226 .where_(Employee::name_r(), |name| name.to_lowercase().contains("alice"));
227 let ilike = ilike_query.all();
228
229 let test14_pass = ilike.len() == 2;
230 print_test("Case-insensitive LIKE works correctly", test14_pass);
231 println!(" Found {} employees with 'alice' (case-insensitive)", ilike.len());
232
233 // TEST 15: LIMIT produces exact subset
234 println!("\nTest 15: LIMIT clause");
235 println!("SQL: SELECT * FROM employees ORDER BY salary DESC LIMIT 3;");
236
237 let limited = Query::new(&employees)
238 .order_by_float_desc(Employee::salary_r())
239 .into_iter()
240 .take(3)
241 .collect::<Vec<_>>();
242
243 let test15_pass = limited.len() == 3
244 && limited[0].salary == 105000.0
245 && limited[1].salary == 95000.0
246 && limited[2].salary == 87000.0;
247 print_test("LIMIT returns correct top-N results", test15_pass);
248 println!(" Top 3 salaries: ${:.0}, ${:.0}, ${:.0}",
249 limited[0].salary, limited[1].salary, limited[2].salary);
250
251 // TEST 16: GROUP BY produces correct groups
252 println!("\nTest 16: GROUP BY");
253 println!("SQL: SELECT department, COUNT(*) FROM employees GROUP BY department;");
254
255 let grouped = Query::new(&employees).group_by(Employee::department_r());
256 let eng_count = grouped.get("Engineering").map(|v| v.len()).unwrap_or(0);
257 let sales_count = grouped.get("Sales").map(|v| v.len()).unwrap_or(0);
258 let marketing_count = grouped.get("Marketing").map(|v| v.len()).unwrap_or(0);
259
260 let test16_pass = eng_count == 3 && sales_count == 2 && marketing_count == 1;
261 print_test("GROUP BY produces correct counts", test16_pass);
262 println!(" Engineering: {}, Sales: {}, Marketing: {}", eng_count, sales_count, marketing_count);
263
264 // TEST 17: Email pattern matching (regex-like)
265 println!("\nTest 17: Email domain filtering (LIKE '%@example.com')");
266 println!("SQL: SELECT * FROM employees WHERE email LIKE '%@example.com';");
267
268 let example_emails = Query::new(&employees)
269 .where_(Employee::email_r(), |email| email.ends_with("@example.com"))
270 .count();
271
272 let test17_pass = example_emails == 6; // All employees have @example.com emails
273 print_test("Email pattern matching works correctly", test17_pass);
274 println!(" Found {} employees with @example.com emails", example_emails);
275
276 // Summary
277 println!("\n╔════════════════════════════════════════════════════════════════╗");
278 println!("║ Test Summary ║");
279 println!("╚════════════════════════════════════════════════════════════════╝\n");
280
281 let tests = vec![
282 ("ORDER BY DESC", test1_pass),
283 ("ORDER BY ASC", test2_pass),
284 ("ORDER BY name", test3_pass),
285 ("LIKE 'prefix%'", test4_pass),
286 ("LIKE '%suffix'", test5_pass),
287 ("LIKE '%contains%'", test6_pass),
288 ("IN clause", test7_pass),
289 ("BETWEEN clause", test8_pass),
290 ("COUNT", test9_pass),
291 ("AVG accuracy", test10_pass),
292 ("MIN/MAX", test11_pass),
293 ("Complex WHERE", test12_pass),
294 ("Case-sensitive", test13_pass),
295 ("Case-insensitive", test14_pass),
296 ("LIMIT", test15_pass),
297 ("GROUP BY", test16_pass),
298 ("Email patterns", test17_pass),
299 ];
300
301 let passed = tests.iter().filter(|(_, p)| *p).count();
302 let total = tests.len();
303
304 println!("Results: {}/{} tests passed", passed, total);
305
306 if passed == total {
307 println!("\n🎉 All tests PASSED! Rust Query Builder produces exact SQL-equivalent results!");
308 println!("\n✅ Verified:");
309 println!(" • Exact ordering (ASC/DESC)");
310 println!(" • LIKE operations (starts_with, ends_with, contains)");
311 println!(" • IN clause (OR conditions)");
312 println!(" • BETWEEN clause");
313 println!(" • Aggregations (COUNT, AVG, MIN, MAX)");
314 println!(" • Complex WHERE conditions");
315 println!(" • Case sensitivity");
316 println!(" • LIMIT clause");
317 println!(" • GROUP BY");
318 println!(" • Pattern matching");
319 } else {
320 println!("\n⚠️ {} test(s) failed. See details above.", total - passed);
321 }
322}Sourcepub fn order_by_float_desc(&self, path: KeyPaths<T, f64>) -> Vec<T>
pub fn order_by_float_desc(&self, path: KeyPaths<T, f64>) -> Vec<T>
Orders results by a float field in descending order.
Note: This method requires T: Clone as it creates owned sorted copies.
§Arguments
path- The key-path to the f64 field to order by
§Example
let sorted = query.order_by_float_desc(Product::rating_r());Examples found in repository?
110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}More examples
33fn main() {
34 let employees = create_test_data();
35
36 println!("\n╔════════════════════════════════════════════════════════════════╗");
37 println!("║ SQL Equivalence Verification Tests ║");
38 println!("╚════════════════════════════════════════════════════════════════╝\n");
39
40 // TEST 1: ORDER BY maintains exact SQL ordering (DESC)
41 println!("Test 1: ORDER BY DESC - Exact ordering");
42 println!("SQL: SELECT * FROM employees ORDER BY salary DESC;");
43
44 let ordered = Query::new(&employees).order_by_float_desc(Employee::salary_r());
45 let expected_order = vec![105000.0, 95000.0, 87000.0, 82000.0, 75000.0, 71000.0];
46 let actual_order: Vec<f64> = ordered.iter().map(|e| e.salary).collect();
47
48 let test1_pass = expected_order == actual_order;
49 print_test("ORDER BY salary DESC produces correct order", test1_pass);
50 if !test1_pass {
51 println!(" Expected: {:?}", expected_order);
52 println!(" Got: {:?}", actual_order);
53 }
54
55 // TEST 2: ORDER BY maintains exact SQL ordering (ASC)
56 println!("\nTest 2: ORDER BY ASC - Exact ordering");
57 println!("SQL: SELECT * FROM employees ORDER BY salary ASC;");
58
59 let ordered_asc = Query::new(&employees).order_by_float(Employee::salary_r());
60 let expected_asc = vec![71000.0, 75000.0, 82000.0, 87000.0, 95000.0, 105000.0];
61 let actual_asc: Vec<f64> = ordered_asc.iter().map(|e| e.salary).collect();
62
63 let test2_pass = expected_asc == actual_asc;
64 print_test("ORDER BY salary ASC produces correct order", test2_pass);
65 if !test2_pass {
66 println!(" Expected: {:?}", expected_asc);
67 println!(" Got: {:?}", actual_asc);
68 }
69
70 // TEST 3: String ordering (alphabetical)
71 println!("\nTest 3: ORDER BY name (alphabetical)");
72 println!("SQL: SELECT name FROM employees ORDER BY name;");
73
74 let ordered_names = Query::new(&employees).order_by(Employee::name_r());
75 let expected_names = vec!["Alice Cooper", "Alice Johnson", "Bob Smith", "Carol White", "David Brown", "Eve Davis"];
76 let actual_names: Vec<&str> = ordered_names.iter().map(|e| e.name.as_str()).collect();
77
78 let test3_pass = expected_names == actual_names;
79 print_test("ORDER BY name produces correct alphabetical order", test3_pass);
80 if !test3_pass {
81 println!(" Expected: {:?}", expected_names);
82 println!(" Got: {:?}", actual_names);
83 }
84
85 // TEST 4: LIKE equivalent - starts with
86 println!("\nTest 4: LIKE 'Alice%' equivalent");
87 println!("SQL: SELECT * FROM employees WHERE name LIKE 'Alice%';");
88
89 let like_alice_query = Query::new(&employees)
90 .where_(Employee::name_r(), |name| name.starts_with("Alice"));
91 let like_alice = like_alice_query.all();
92
93 let test4_pass = like_alice.len() == 2
94 && like_alice.iter().all(|e| e.name.starts_with("Alice"));
95 print_test("LIKE 'Alice%' (starts_with) works correctly", test4_pass);
96 if test4_pass {
97 for emp in &like_alice {
98 println!(" Found: {}", emp.name);
99 }
100 }
101
102 // TEST 5: LIKE equivalent - ends with
103 println!("\nTest 5: LIKE '%son' equivalent");
104 println!("SQL: SELECT * FROM employees WHERE name LIKE '%son';");
105
106 let like_son_query = Query::new(&employees)
107 .where_(Employee::name_r(), |name| name.ends_with("son"));
108 let like_son = like_son_query.all();
109
110 let test5_pass = like_son.len() == 1 && like_son[0].name == "Alice Johnson";
111 print_test("LIKE '%son' (ends_with) works correctly", test5_pass);
112 if test5_pass {
113 for emp in &like_son {
114 println!(" Found: {}", emp.name);
115 }
116 }
117
118 // TEST 6: LIKE equivalent - contains
119 println!("\nTest 6: LIKE '%mit%' equivalent");
120 println!("SQL: SELECT * FROM employees WHERE name LIKE '%mit%';");
121
122 let like_mit_query = Query::new(&employees)
123 .where_(Employee::name_r(), |name| name.contains("mit"));
124 let like_mit = like_mit_query.all();
125
126 let test6_pass = like_mit.len() == 1 && like_mit[0].name == "Bob Smith";
127 print_test("LIKE '%mit%' (contains) works correctly", test6_pass);
128 if test6_pass {
129 for emp in &like_mit {
130 println!(" Found: {}", emp.name);
131 }
132 }
133
134 // TEST 7: IN clause equivalent
135 println!("\nTest 7: IN clause equivalent");
136 println!("SQL: SELECT * FROM employees WHERE department IN ('Engineering', 'Sales');");
137
138 let in_depts_query = Query::new(&employees)
139 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales");
140 let in_depts = in_depts_query.all();
141
142 let test7_pass = in_depts.len() == 5 // 3 Engineering + 2 Sales
143 && in_depts.iter().all(|e| e.department == "Engineering" || e.department == "Sales");
144 print_test("IN clause works correctly", test7_pass);
145 println!(" Found {} employees in Engineering or Sales", in_depts.len());
146
147 // TEST 8: BETWEEN equivalent
148 println!("\nTest 8: BETWEEN clause equivalent");
149 println!("SQL: SELECT * FROM employees WHERE salary BETWEEN 75000 AND 90000;");
150
151 let between_query = Query::new(&employees)
152 .where_(Employee::salary_r(), |&sal| sal >= 75000.0 && sal <= 90000.0);
153 let between = between_query.all();
154
155 let test8_pass = between.len() == 3;
156 print_test("BETWEEN clause works correctly", test8_pass);
157 println!(" Found {} employees with salary between 75K-90K", between.len());
158
159 // TEST 9: COUNT with WHERE
160 println!("\nTest 9: COUNT with WHERE");
161 println!("SQL: SELECT COUNT(*) FROM employees WHERE department = 'Engineering';");
162
163 let count_eng = Query::new(&employees)
164 .where_(Employee::department_r(), |dept| dept == "Engineering")
165 .count();
166
167 let test9_pass = count_eng == 3;
168 print_test("COUNT with WHERE produces correct result", test9_pass);
169 println!(" Count: {} (expected 3)", count_eng);
170
171 // TEST 10: AVG produces exact result
172 println!("\nTest 10: AVG aggregation accuracy");
173 println!("SQL: SELECT AVG(salary) FROM employees WHERE department = 'Engineering';");
174
175 let avg_sal = Query::new(&employees)
176 .where_(Employee::department_r(), |dept| dept == "Engineering")
177 .avg(Employee::salary_r())
178 .unwrap_or(0.0);
179
180 let expected_avg = (95000.0 + 87000.0 + 105000.0) / 3.0;
181 let test10_pass = (avg_sal - expected_avg).abs() < 0.01;
182 print_test("AVG produces mathematically correct result", test10_pass);
183 println!(" Average: ${:.2} (expected ${:.2})", avg_sal, expected_avg);
184
185 // TEST 11: MIN and MAX
186 println!("\nTest 11: MIN and MAX aggregations");
187 println!("SQL: SELECT MIN(salary), MAX(salary) FROM employees;");
188
189 let min_sal = Query::new(&employees).min_float(Employee::salary_r()).unwrap_or(0.0);
190 let max_sal = Query::new(&employees).max_float(Employee::salary_r()).unwrap_or(0.0);
191
192 let test11_pass = min_sal == 71000.0 && max_sal == 105000.0;
193 print_test("MIN and MAX produce correct results", test11_pass);
194 println!(" MIN: ${:.2}, MAX: ${:.2}", min_sal, max_sal);
195
196 // TEST 12: Complex WHERE with AND/OR
197 println!("\nTest 12: Complex WHERE (AND + OR)");
198 println!("SQL: SELECT * FROM employees WHERE (department = 'Engineering' OR department = 'Sales') AND salary > 80000;");
199
200 let complex_query = Query::new(&employees)
201 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
202 .where_(Employee::salary_r(), |&sal| sal > 80000.0);
203 let complex = complex_query.all();
204
205 let test12_pass = complex.len() == 4; // Alice J ($95k), Bob ($87k), David ($82k), Alice C ($105k)
206 print_test("Complex WHERE clause works correctly", test12_pass);
207 println!(" Found {} employees", complex.len());
208
209 // TEST 13: Case-sensitive string comparison (SQL default)
210 println!("\nTest 13: Case-sensitive comparison (like SQL)");
211 println!("SQL: SELECT * FROM employees WHERE department = 'engineering'; -- should find 0");
212
213 let case_sensitive = Query::new(&employees)
214 .where_(Employee::department_r(), |dept| dept == "engineering") // lowercase
215 .count();
216
217 let test13_pass = case_sensitive == 0;
218 print_test("Case-sensitive comparison (SQL default)", test13_pass);
219 println!(" Found {} with lowercase 'engineering' (expected 0)", case_sensitive);
220
221 // TEST 14: Case-insensitive LIKE equivalent
222 println!("\nTest 14: Case-insensitive LIKE (ILIKE equivalent)");
223 println!("SQL: SELECT * FROM employees WHERE LOWER(name) LIKE '%alice%';");
224
225 let ilike_query = Query::new(&employees)
226 .where_(Employee::name_r(), |name| name.to_lowercase().contains("alice"));
227 let ilike = ilike_query.all();
228
229 let test14_pass = ilike.len() == 2;
230 print_test("Case-insensitive LIKE works correctly", test14_pass);
231 println!(" Found {} employees with 'alice' (case-insensitive)", ilike.len());
232
233 // TEST 15: LIMIT produces exact subset
234 println!("\nTest 15: LIMIT clause");
235 println!("SQL: SELECT * FROM employees ORDER BY salary DESC LIMIT 3;");
236
237 let limited = Query::new(&employees)
238 .order_by_float_desc(Employee::salary_r())
239 .into_iter()
240 .take(3)
241 .collect::<Vec<_>>();
242
243 let test15_pass = limited.len() == 3
244 && limited[0].salary == 105000.0
245 && limited[1].salary == 95000.0
246 && limited[2].salary == 87000.0;
247 print_test("LIMIT returns correct top-N results", test15_pass);
248 println!(" Top 3 salaries: ${:.0}, ${:.0}, ${:.0}",
249 limited[0].salary, limited[1].salary, limited[2].salary);
250
251 // TEST 16: GROUP BY produces correct groups
252 println!("\nTest 16: GROUP BY");
253 println!("SQL: SELECT department, COUNT(*) FROM employees GROUP BY department;");
254
255 let grouped = Query::new(&employees).group_by(Employee::department_r());
256 let eng_count = grouped.get("Engineering").map(|v| v.len()).unwrap_or(0);
257 let sales_count = grouped.get("Sales").map(|v| v.len()).unwrap_or(0);
258 let marketing_count = grouped.get("Marketing").map(|v| v.len()).unwrap_or(0);
259
260 let test16_pass = eng_count == 3 && sales_count == 2 && marketing_count == 1;
261 print_test("GROUP BY produces correct counts", test16_pass);
262 println!(" Engineering: {}, Sales: {}, Marketing: {}", eng_count, sales_count, marketing_count);
263
264 // TEST 17: Email pattern matching (regex-like)
265 println!("\nTest 17: Email domain filtering (LIKE '%@example.com')");
266 println!("SQL: SELECT * FROM employees WHERE email LIKE '%@example.com';");
267
268 let example_emails = Query::new(&employees)
269 .where_(Employee::email_r(), |email| email.ends_with("@example.com"))
270 .count();
271
272 let test17_pass = example_emails == 6; // All employees have @example.com emails
273 print_test("Email pattern matching works correctly", test17_pass);
274 println!(" Found {} employees with @example.com emails", example_emails);
275
276 // Summary
277 println!("\n╔════════════════════════════════════════════════════════════════╗");
278 println!("║ Test Summary ║");
279 println!("╚════════════════════════════════════════════════════════════════╝\n");
280
281 let tests = vec![
282 ("ORDER BY DESC", test1_pass),
283 ("ORDER BY ASC", test2_pass),
284 ("ORDER BY name", test3_pass),
285 ("LIKE 'prefix%'", test4_pass),
286 ("LIKE '%suffix'", test5_pass),
287 ("LIKE '%contains%'", test6_pass),
288 ("IN clause", test7_pass),
289 ("BETWEEN clause", test8_pass),
290 ("COUNT", test9_pass),
291 ("AVG accuracy", test10_pass),
292 ("MIN/MAX", test11_pass),
293 ("Complex WHERE", test12_pass),
294 ("Case-sensitive", test13_pass),
295 ("Case-insensitive", test14_pass),
296 ("LIMIT", test15_pass),
297 ("GROUP BY", test16_pass),
298 ("Email patterns", test17_pass),
299 ];
300
301 let passed = tests.iter().filter(|(_, p)| *p).count();
302 let total = tests.len();
303
304 println!("Results: {}/{} tests passed", passed, total);
305
306 if passed == total {
307 println!("\n🎉 All tests PASSED! Rust Query Builder produces exact SQL-equivalent results!");
308 println!("\n✅ Verified:");
309 println!(" • Exact ordering (ASC/DESC)");
310 println!(" • LIKE operations (starts_with, ends_with, contains)");
311 println!(" • IN clause (OR conditions)");
312 println!(" • BETWEEN clause");
313 println!(" • Aggregations (COUNT, AVG, MIN, MAX)");
314 println!(" • Complex WHERE conditions");
315 println!(" • Case sensitivity");
316 println!(" • LIMIT clause");
317 println!(" • GROUP BY");
318 println!(" • Pattern matching");
319 } else {
320 println!("\n⚠️ {} test(s) failed. See details above.", total - passed);
321 }
322}84fn main() {
85 let employees = create_employees();
86 let departments = create_departments();
87 let projects = create_projects();
88
89 println!("\n╔════════════════════════════════════════════════════════════════════════╗");
90 println!("║ SQL vs Rust Query Builder Comparison ║");
91 println!("║ Demonstrating equivalent operations ║");
92 println!("╚════════════════════════════════════════════════════════════════════════╝");
93
94 // ============================================================================
95 // EXAMPLE 1: Simple SELECT with WHERE
96 // ============================================================================
97 print_separator("Example 1: SELECT with WHERE clause");
98 print_query(
99 "SELECT * FROM employees WHERE department = 'Engineering';",
100 "Filter employees by department"
101 );
102
103 let eng_query = Query::new(&employees)
104 .where_(Employee::department_r(), |dept| dept == "Engineering");
105 let engineering_employees = eng_query.all();
106
107 for emp in &engineering_employees {
108 println!(" ID: {}, Name: {}, Salary: ${:.2}", emp.id, emp.name, emp.salary);
109 }
110 println!("\nRust Query Builder:");
111 println!("Query::new(&employees)");
112 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\")");
113 println!(" .all()");
114 println!("✓ Found {} employees", engineering_employees.len());
115
116 // ============================================================================
117 // EXAMPLE 2: SELECT specific columns
118 // ============================================================================
119 print_separator("Example 2: SELECT specific columns (Projection)");
120 print_query(
121 "SELECT name FROM employees WHERE salary > 80000;",
122 "Get names of high-earning employees"
123 );
124
125 let high_earners = Query::new(&employees)
126 .where_(Employee::salary_r(), |&salary| salary > 80000.0)
127 .select(Employee::name_r());
128
129 for name in &high_earners {
130 println!(" {}", name);
131 }
132 println!("\nRust Query Builder:");
133 println!("Query::new(&employees)");
134 println!(" .where_(Employee::salary_r(), |&salary| salary > 80000.0)");
135 println!(" .select(Employee::name_r())");
136 println!("✓ Found {} employees", high_earners.len());
137
138 // ============================================================================
139 // EXAMPLE 3: COUNT
140 // ============================================================================
141 print_separator("Example 3: COUNT aggregation");
142 print_query(
143 "SELECT COUNT(*) FROM employees WHERE age < 30;",
144 "Count young employees"
145 );
146
147 let young_count = Query::new(&employees)
148 .where_(Employee::age_r(), |&age| age < 30)
149 .count();
150
151 println!(" Count: {}", young_count);
152 println!("\nRust Query Builder:");
153 println!("Query::new(&employees)");
154 println!(" .where_(Employee::age_r(), |&age| age < 30)");
155 println!(" .count()");
156 println!("✓ Result: {}", young_count);
157
158 // ============================================================================
159 // EXAMPLE 4: SUM, AVG, MIN, MAX
160 // ============================================================================
161 print_separator("Example 4: Aggregate functions (SUM, AVG, MIN, MAX)");
162 print_query(
163 "SELECT \n\
164 SUM(salary) as total_salary,\n\
165 AVG(salary) as avg_salary,\n\
166 MIN(salary) as min_salary,\n\
167 MAX(salary) as max_salary\n\
168 FROM employees WHERE department = 'Engineering';",
169 "Engineering department salary statistics"
170 );
171
172 let eng_query = Query::new(&employees)
173 .where_(Employee::department_r(), |dept| dept == "Engineering");
174
175 let total = eng_query.sum(Employee::salary_r());
176 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
177 let min = eng_query.min_float(Employee::salary_r()).unwrap_or(0.0);
178 let max = eng_query.max_float(Employee::salary_r()).unwrap_or(0.0);
179
180 println!(" Total Salary: ${:.2}", total);
181 println!(" Avg Salary: ${:.2}", avg);
182 println!(" Min Salary: ${:.2}", min);
183 println!(" Max Salary: ${:.2}", max);
184
185 println!("\nRust Query Builder:");
186 println!("let query = Query::new(&employees)");
187 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\");");
188 println!("query.sum(Employee::salary_r()) // ${:.2}", total);
189 println!("query.avg(Employee::salary_r()) // ${:.2}", avg);
190 println!("query.min_float(Employee::salary_r()) // ${:.2}", min);
191 println!("query.max_float(Employee::salary_r()) // ${:.2}", max);
192
193 // ============================================================================
194 // EXAMPLE 5: GROUP BY with aggregation
195 // ============================================================================
196 print_separator("Example 5: GROUP BY with aggregation");
197 print_query(
198 "SELECT \n\
199 department,\n\
200 COUNT(*) as emp_count,\n\
201 AVG(salary) as avg_salary\n\
202 FROM employees\n\
203 GROUP BY department;",
204 "Statistics by department"
205 );
206
207 let by_dept = Query::new(&employees).group_by(Employee::department_r());
208
209 for (dept, emps) in &by_dept {
210 let dept_query = Query::new(emps);
211 let count = emps.len();
212 let avg_sal = dept_query.avg(Employee::salary_r()).unwrap_or(0.0);
213 println!(" {}: {} employees, avg salary ${:.2}", dept, count, avg_sal);
214 }
215
216 println!("\nRust Query Builder:");
217 println!("let by_dept = Query::new(&employees).group_by(Employee::department_r());");
218 println!("for (dept, emps) in &by_dept {{");
219 println!(" let dept_query = Query::new(emps);");
220 println!(" dept_query.avg(Employee::salary_r())");
221 println!("}}");
222
223 // ============================================================================
224 // EXAMPLE 6: ORDER BY
225 // ============================================================================
226 print_separator("Example 6: ORDER BY");
227 print_query(
228 "SELECT name, salary FROM employees\n\
229 WHERE department = 'Sales'\n\
230 ORDER BY salary DESC;",
231 "Sales employees ordered by salary (descending)"
232 );
233
234 let sales_sorted = Query::new(&employees)
235 .where_(Employee::department_r(), |dept| dept == "Sales")
236 .order_by_float_desc(Employee::salary_r());
237
238 for emp in &sales_sorted {
239 println!(" {}: ${:.2}", emp.name, emp.salary);
240 }
241
242 println!("\nRust Query Builder:");
243 println!("Query::new(&employees)");
244 println!(" .where_(Employee::department_r(), |dept| dept == \"Sales\")");
245 println!(" .order_by_float_desc(Employee::salary_r())");
246
247 // ============================================================================
248 // EXAMPLE 7: Multiple WHERE conditions (AND)
249 // ============================================================================
250 print_separator("Example 7: Multiple WHERE conditions (AND)");
251 print_query(
252 "SELECT * FROM employees\n\
253 WHERE salary > 70000 AND age < 35;",
254 "High-earning young employees"
255 );
256
257 let filter_query = Query::new(&employees)
258 .where_(Employee::salary_r(), |&salary| salary > 70000.0)
259 .where_(Employee::age_r(), |&age| age < 35);
260 let filtered = filter_query.all();
261
262 for emp in &filtered {
263 println!(" {}: Age {}, Salary ${:.2}", emp.name, emp.age, emp.salary);
264 }
265
266 println!("\nRust Query Builder:");
267 println!("Query::new(&employees)");
268 println!(" .where_(Employee::salary_r(), |&salary| salary > 70000.0)");
269 println!(" .where_(Employee::age_r(), |&age| age < 35)");
270 println!(" .all()");
271 println!("✓ Found {} employees", filtered.len());
272
273 // ============================================================================
274 // EXAMPLE 8: LIMIT (TOP N)
275 // ============================================================================
276 print_separator("Example 8: LIMIT / TOP N");
277 print_query(
278 "SELECT TOP 3 name, salary FROM employees\n\
279 ORDER BY salary DESC;",
280 "Top 3 highest paid employees"
281 );
282
283 let top_earners = Query::new(&employees)
284 .order_by_float_desc(Employee::salary_r());
285
286 for (i, emp) in top_earners.iter().take(3).enumerate() {
287 println!(" {}. {}: ${:.2}", i + 1, emp.name, emp.salary);
288 }
289
290 println!("\nRust Query Builder:");
291 println!("Query::new(&employees)");
292 println!(" .order_by_float_desc(Employee::salary_r())");
293 println!(" .into_iter().take(3)");
294
295 // ============================================================================
296 // EXAMPLE 9: OFFSET and LIMIT (Pagination)
297 // ============================================================================
298 print_separator("Example 9: OFFSET and LIMIT (Pagination)");
299 print_query(
300 "SELECT name FROM employees\n\
301 ORDER BY name\n\
302 LIMIT 3 OFFSET 3;",
303 "Page 2 of employee names (3 per page)"
304 );
305
306 let page_2 = Query::new(&employees)
307 .order_by(Employee::name_r())
308 .into_iter()
309 .skip(3)
310 .take(3)
311 .collect::<Vec<_>>();
312
313 for emp in &page_2 {
314 println!(" {}", emp.name);
315 }
316
317 println!("\nRust Query Builder:");
318 println!("Query::new(&employees)");
319 println!(" .order_by(Employee::name_r())");
320 println!(" .into_iter().skip(3).take(3)");
321
322 // ============================================================================
323 // EXAMPLE 10: INNER JOIN
324 // ============================================================================
325 print_separator("Example 10: INNER JOIN");
326 print_query(
327 "SELECT e.name, d.name as dept_name, d.budget\n\
328 FROM employees e\n\
329 INNER JOIN departments d ON e.department = d.name;",
330 "Employees with their department info"
331 );
332
333 let emp_dept = JoinQuery::new(&employees, &departments).inner_join(
334 Employee::department_r(),
335 Department::name_r(),
336 |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget),
337 );
338
339 for (emp_name, dept_name, budget) in emp_dept.iter().take(5) {
340 println!(" {} works in {} (Budget: ${:.0})", emp_name, dept_name, budget);
341 }
342 println!(" ... (showing first 5)");
343
344 println!("\nRust Query Builder:");
345 println!("JoinQuery::new(&employees, &departments).inner_join(");
346 println!(" Employee::department_r(),");
347 println!(" Department::name_r(),");
348 println!(" |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget)");
349 println!(")");
350 println!("✓ Found {} matches", emp_dept.len());
351
352 // ============================================================================
353 // EXAMPLE 11: GROUP BY with HAVING equivalent
354 // ============================================================================
355 print_separator("Example 11: GROUP BY with filtering (HAVING equivalent)");
356 print_query(
357 "SELECT city, COUNT(*) as emp_count, AVG(salary) as avg_salary\n\
358 FROM employees\n\
359 GROUP BY city\n\
360 HAVING COUNT(*) > 1;",
361 "Cities with multiple employees"
362 );
363
364 let by_city = Query::new(&employees).group_by(Employee::city_r());
365 let mut city_stats: Vec<_> = by_city
366 .iter()
367 .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent
368 .map(|(city, emps)| {
369 let avg_sal = Query::new(emps).avg(Employee::salary_r()).unwrap_or(0.0);
370 (city.clone(), emps.len(), avg_sal)
371 })
372 .collect();
373
374 city_stats.sort_by(|a, b| b.1.cmp(&a.1)); // Sort by count
375
376 for (city, count, avg_sal) in &city_stats {
377 println!(" {}: {} employees, avg salary ${:.2}", city, count, avg_sal);
378 }
379
380 println!("\nRust Query Builder:");
381 println!("let by_city = Query::new(&employees).group_by(Employee::city_r());");
382 println!("by_city.iter()");
383 println!(" .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent");
384 println!(" .map(|(city, emps)| {{");
385 println!(" let avg = Query::new(emps).avg(Employee::salary_r());");
386 println!(" (city, emps.len(), avg)");
387 println!(" }})");
388
389 // ============================================================================
390 // EXAMPLE 12: Complex query with multiple operations
391 // ============================================================================
392 print_separator("Example 12: Complex multi-operation query");
393 print_query(
394 "SELECT name, salary, age\n\
395 FROM employees\n\
396 WHERE department IN ('Engineering', 'Sales')\n\
397 AND salary BETWEEN 80000 AND 100000\n\
398 AND age >= 30\n\
399 ORDER BY salary DESC;",
400 "Experienced mid-to-senior level employees in core departments"
401 );
402
403 let complex_query = Query::new(&employees)
404 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
405 .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)
406 .where_(Employee::age_r(), |&age| age >= 30)
407 .order_by_float_desc(Employee::salary_r());
408
409 for emp in &complex_query {
410 println!(" {}: Age {}, {} dept, ${:.2}", emp.name, emp.age, emp.department, emp.salary);
411 }
412
413 println!("\nRust Query Builder:");
414 println!("Query::new(&employees)");
415 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\" || dept == \"Sales\")");
416 println!(" .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)");
417 println!(" .where_(Employee::age_r(), |&age| age >= 30)");
418 println!(" .order_by_float_desc(Employee::salary_r())");
419 println!("✓ Found {} employees", complex_query.len());
420
421 // ============================================================================
422 // EXAMPLE 13: Three-table JOIN
423 // ============================================================================
424 print_separator("Example 13: Three-table JOIN");
425 print_query(
426 "SELECT p.name as project, d.name as department, d.location\n\
427 FROM projects p\n\
428 INNER JOIN departments d ON p.department_id = d.id;",
429 "Projects with their department details"
430 );
431
432 let proj_dept = JoinQuery::new(&projects, &departments).inner_join(
433 Project::department_id_r(),
434 Department::id_r(),
435 |proj, dept| {
436 (proj.name.clone(), dept.name.clone(), dept.location.clone(), proj.budget)
437 },
438 );
439
440 for (proj_name, dept_name, location, budget) in &proj_dept {
441 println!(" {}: {} dept in {} (${:.0})", proj_name, dept_name, location, budget);
442 }
443
444 println!("\nRust Query Builder:");
445 println!("JoinQuery::new(&projects, &departments).inner_join(");
446 println!(" Project::department_id_r(),");
447 println!(" Department::id_r(),");
448 println!(" |proj, dept| (proj.name, dept.name, dept.location, proj.budget)");
449 println!(")");
450
451 // ============================================================================
452 // EXAMPLE 14: Subquery equivalent (using intermediate results)
453 // ============================================================================
454 print_separator("Example 14: Subquery equivalent");
455 print_query(
456 "SELECT * FROM employees\n\
457 WHERE salary > (SELECT AVG(salary) FROM employees);",
458 "Employees earning above average"
459 );
460
461 let avg_salary = Query::new(&employees)
462 .avg(Employee::salary_r())
463 .unwrap_or(0.0);
464
465 let above_avg_query = Query::new(&employees)
466 .where_(Employee::salary_r(), move |&sal| sal > avg_salary);
467 let above_avg = above_avg_query.all();
468
469 println!(" Average salary: ${:.2}", avg_salary);
470 for emp in &above_avg {
471 println!(" {}: ${:.2} ({:.1}% above average)",
472 emp.name, emp.salary, ((emp.salary - avg_salary) / avg_salary * 100.0));
473 }
474
475 println!("\nRust Query Builder:");
476 println!("let avg = Query::new(&employees).avg(Employee::salary_r()).unwrap_or(0.0);");
477 println!("Query::new(&employees)");
478 println!(" .where_(Employee::salary_r(), |&sal| sal > avg)");
479 println!(" .all()");
480 println!("✓ Found {} employees above average", above_avg.len());
481
482 // ============================================================================
483 // EXAMPLE 15: Advanced aggregation (revenue calculation)
484 // ============================================================================
485 print_separator("Example 15: Advanced aggregation");
486 print_query(
487 "SELECT \n\
488 d.name,\n\
489 d.budget as dept_budget,\n\
490 SUM(p.budget) as total_project_budget,\n\
491 (d.budget - SUM(p.budget)) as remaining_budget\n\
492 FROM departments d\n\
493 LEFT JOIN projects p ON d.id = p.department_id\n\
494 GROUP BY d.name, d.budget;",
495 "Department budget utilization"
496 );
497
498 // Join departments with projects
499 let dept_projects = JoinQuery::new(&departments, &projects).left_join(
500 Department::id_r(),
501 Project::department_id_r(),
502 |dept, proj| (dept.clone(), proj.map(|p| p.clone())),
503 );
504
505 // Aggregate by department
506 let mut dept_budget_map: HashMap<String, (f64, Vec<f64>)> = HashMap::new();
507 for (dept, proj) in dept_projects {
508 let entry = dept_budget_map
509 .entry(dept.name.clone())
510 .or_insert((dept.budget, Vec::new()));
511 if let Some(p) = proj {
512 entry.1.push(p.budget);
513 }
514 }
515
516 for (dept_name, (total_budget, project_budgets)) in dept_budget_map.iter() {
517 let used: f64 = project_budgets.iter().sum();
518 let remaining = total_budget - used;
519 println!(" {}: Budget ${:.0}, Used ${:.0}, Remaining ${:.0} ({:.1}% utilized)",
520 dept_name, total_budget, used, remaining, (used / total_budget * 100.0));
521 }
522
523 println!("\nRust Query Builder:");
524 println!("let dept_projects = JoinQuery::new(&departments, &projects)");
525 println!(" .left_join(Department::id_r(), Project::department_id_r(), ...)");
526 println!("// Then aggregate using HashMap");
527
528 // ============================================================================
529 // Summary
530 // ============================================================================
531 print_separator("Summary");
532 println!("\n✓ All 15 SQL queries successfully replicated with Rust Query Builder!");
533 println!("\nDemonstrated equivalents for:");
534 println!(" • SELECT with WHERE");
535 println!(" • Projection (SELECT specific columns)");
536 println!(" • Aggregations (COUNT, SUM, AVG, MIN, MAX)");
537 println!(" • GROUP BY");
538 println!(" • ORDER BY");
539 println!(" • LIMIT and OFFSET");
540 println!(" • INNER JOIN and LEFT JOIN");
541 println!(" • Complex conditions (AND, OR, BETWEEN)");
542 println!(" • Subqueries");
543 println!(" • Multi-table operations");
544 println!("\n🎯 Type-safe, compile-time checked, and zero runtime overhead!");
545 println!();
546}98fn main() {
99 println!("\n╔═══════════════════════════════════════════════════════════════╗");
100 println!("║ Memory Safety Verification ║");
101 println!("║ Proving 'static doesn't cause memory leaks ║");
102 println!("╚═══════════════════════════════════════════════════════════════╝\n");
103
104 println!("🔍 Understanding 'static:\n");
105 println!(" • T: 'static means: Type T doesn't contain non-'static references");
106 println!(" • It does NOT mean: Data lives for entire program");
107 println!(" • It's needed for: Storing types in trait objects");
108 println!(" • Safety: Compiler ensures no dangling references\n");
109
110 // ============================================================================
111 // TEST 1: Basic Query - Verify Cleanup
112 // ============================================================================
113 println!("═══════════════════════════════════════════════════════════════");
114 println!("Test 1: Basic WHERE query - verify all data is dropped");
115 println!("═══════════════════════════════════════════════════════════════\n");
116
117 reset_stats();
118 {
119 let employees = vec![
120 create_employee(1, "Alice", "Engineering", 95000.0),
121 create_employee(2, "Bob", "Engineering", 87000.0),
122 create_employee(3, "Carol", "Sales", 75000.0),
123 ];
124 print_memory_status("After creating employees");
125
126 {
127 let query = Query::new(&employees)
128 .where_(Employee::department_r(), |dept| dept == "Engineering");
129 let results = query.all();
130
131 println!(" Found {} engineering employees", results.len());
132 print_memory_status("During query execution");
133 }
134
135 print_memory_status("After query scope ends");
136 }
137
138 print_memory_status("After employees scope ends");
139 println!();
140
141 // ============================================================================
142 // TEST 2: Multiple Queries - No Accumulation
143 // ============================================================================
144 println!("═══════════════════════════════════════════════════════════════");
145 println!("Test 2: Multiple queries - verify no memory accumulation");
146 println!("═══════════════════════════════════════════════════════════════\n");
147
148 reset_stats();
149 {
150 let employees = vec![
151 create_employee(1, "Alice", "Engineering", 95000.0),
152 create_employee(2, "Bob", "Sales", 75000.0),
153 ];
154
155 let initial_stats = get_stats();
156 println!(" Initial allocations: {}", initial_stats.0);
157
158 // Run 10 queries
159 for i in 1..=10 {
160 let query = Query::new(&employees)
161 .where_(Employee::salary_r(), |&s| s > 70000.0);
162 let _results = query.all();
163
164 if i % 3 == 0 {
165 let (allocs, drops) = get_stats();
166 println!(" After {} queries - Allocated: {}, Dropped: {}", i, allocs, drops);
167 }
168 }
169
170 let final_stats = get_stats();
171 println!("\n After 10 queries:");
172 println!(" Allocations: {} (should be same as initial)", final_stats.0);
173 println!(" ✅ No memory accumulation from queries!");
174 }
175
176 print_memory_status("After all queries and employees dropped");
177 println!();
178
179 // ============================================================================
180 // TEST 3: ORDER BY (requires Clone) - Track Cloning
181 // ============================================================================
182 println!("═══════════════════════════════════════════════════════════════");
183 println!("Test 3: ORDER BY (with Clone) - verify controlled cloning");
184 println!("═══════════════════════════════════════════════════════════════\n");
185
186 reset_stats();
187 {
188 let employees = vec![
189 create_employee(1, "Alice", "Engineering", 95000.0),
190 create_employee(2, "Bob", "Sales", 87000.0),
191 create_employee(3, "Carol", "Marketing", 75000.0),
192 ];
193
194 let (before_allocs, _) = get_stats();
195 println!(" Before sorting: {} allocations", before_allocs);
196
197 {
198 let sorted = Query::new(&employees)
199 .order_by_float_desc(Employee::salary_r());
200
201 let (after_allocs, _) = get_stats();
202 println!(" After sorting: {} allocations", after_allocs);
203 println!(" Cloned items: {} (expected: {})", after_allocs - before_allocs, employees.len());
204 println!(" Sorted {} employees by salary", sorted.len());
205
206 // sorted goes out of scope here
207 }
208
209 print_memory_status("After sorted results dropped");
210 }
211
212 print_memory_status("After employees dropped");
213 println!();
214
215 // ============================================================================
216 // TEST 4: JOIN Operations - No Leaks
217 // ============================================================================
218 println!("═══════════════════════════════════════════════════════════════");
219 println!("Test 4: JOIN operations - verify no memory leaks");
220 println!("═══════════════════════════════════════════════════════════════\n");
221
222 #[derive(Keypaths)]
223 struct Department {
224 id: u32,
225 name: String,
226 drop_tracker: DropTracker,
227 }
228
229 reset_stats();
230 {
231 let employees = vec![
232 create_employee(1, "Alice", "Engineering", 95000.0),
233 create_employee(2, "Bob", "Sales", 87000.0),
234 ];
235
236 let departments = vec![
237 Department {
238 id: 1,
239 name: "Engineering".to_string(),
240 drop_tracker: DropTracker::new(),
241 },
242 Department {
243 id: 2,
244 name: "Sales".to_string(),
245 drop_tracker: DropTracker::new(),
246 },
247 ];
248
249 print_memory_status("After creating data");
250
251 {
252 let results = JoinQuery::new(&employees, &departments)
253 .inner_join(
254 Employee::department_r(),
255 Department::name_r(),
256 |emp, dept| (emp.name.clone(), dept.name.clone()),
257 );
258
259 println!(" Joined {} pairs", results.len());
260 print_memory_status("During join results");
261 }
262
263 print_memory_status("After join results dropped");
264 }
265
266 print_memory_status("After all data dropped");
267 println!();
268
269 // ============================================================================
270 // TEST 5: Large Scale - Memory Behavior
271 // ============================================================================
272 println!("═══════════════════════════════════════════════════════════════");
273 println!("Test 5: Large scale (1000 items) - verify cleanup");
274 println!("═══════════════════════════════════════════════════════════════\n");
275
276 reset_stats();
277 {
278 let mut large_dataset = Vec::new();
279 for i in 0..1000 {
280 large_dataset.push(create_employee(
281 i,
282 &format!("Employee {}", i),
283 if i % 3 == 0 { "Engineering" } else if i % 3 == 1 { "Sales" } else { "Marketing" },
284 50000.0 + (i as f64 * 100.0),
285 ));
286 }
287
288 let (initial_allocs, _) = get_stats();
289 println!(" Created 1000 employees: {} allocations (~10MB)", initial_allocs);
290
291 // Run complex query
292 {
293 let query = Query::new(&large_dataset)
294 .where_(Employee::salary_r(), |&s| s > 80000.0)
295 .where_(Employee::department_r(), |d| d == "Engineering");
296 let results = query.all();
297
298 println!(" Filtered to {} employees", results.len());
299
300 let (during_allocs, _) = get_stats();
301 let extra = during_allocs - initial_allocs;
302 println!(" Extra allocations during query: {} (should be 0)", extra);
303
304 if extra == 0 {
305 println!(" ✅ Zero-copy filtering confirmed!");
306 }
307 }
308
309 print_memory_status("After query results dropped");
310 }
311
312 print_memory_status("After 1000 employees dropped");
313 println!();
314
315 // ============================================================================
316 // TEST 6: Explanation of 'static
317 // ============================================================================
318 println!("═══════════════════════════════════════════════════════════════");
319 println!("Explanation: Why 'static is safe and doesn't leak");
320 println!("═══════════════════════════════════════════════════════════════\n");
321
322 println!("❓ What does T: 'static mean?\n");
323 println!(" WRONG ❌: \"T lives for the entire program\"");
324 println!(" RIGHT ✅: \"T doesn't contain non-'static references\"\n");
325
326 println!("Examples:\n");
327 println!(" struct OwnedData {{ // T: 'static ✅");
328 println!(" id: u32, // Owned data");
329 println!(" name: String, // Owned data");
330 println!(" }}");
331 println!();
332 println!(" struct WithReference<'a> {{ // NOT 'static ❌");
333 println!(" data: &'a String, // Contains reference");
334 println!(" }}");
335 println!();
336
337 println!("Why we use T: 'static:\n");
338 println!(" 1. Store type in trait objects: Box<dyn Fn(&T) -> bool>");
339 println!(" 2. Prevent dangling references in closures");
340 println!(" 3. Ensure type safety at compile time");
341 println!();
342
343 println!("Lifetime of data:\n");
344 println!(" • Data is owned by your Vec<T>");
345 println!(" • Query just borrows &'a [T]");
346 println!(" • When Vec<T> is dropped, all T are dropped");
347 println!(" • No memory leaks possible!\n");
348
349 // ============================================================================
350 // TEST 7: Drop Order Verification
351 // ============================================================================
352 println!("═══════════════════════════════════════════════════════════════");
353 println!("Test 7: Drop order - verify proper RAII");
354 println!("═══════════════════════════════════════════════════════════════\n");
355
356 reset_stats();
357
358 println!("Creating scoped data...");
359 {
360 let employees = vec![
361 create_employee(1, "Alice", "Engineering", 95000.0),
362 create_employee(2, "Bob", "Sales", 87000.0),
363 ];
364 println!(" Created 2 employees");
365
366 {
367 println!(" Creating query...");
368 let query = Query::new(&employees)
369 .where_(Employee::department_r(), |dept| dept == "Engineering");
370
371 {
372 println!(" Executing query...");
373 let results = query.all();
374 println!(" Found {} results", results.len());
375 println!(" Query results going out of scope...");
376 }
377 println!(" Results dropped (just Vec<&Employee>, no Employee drops)");
378
379 println!(" Query going out of scope...");
380 }
381 println!(" Query dropped (just filters, no Employee drops)");
382
383 println!(" Employees vector going out of scope...");
384 }
385 println!(" Employees dropped - NOW Employees are freed!\n");
386
387 let (allocs, drops) = get_stats();
388 println!("Final stats:");
389 println!(" Allocated: {}", allocs);
390 println!(" Dropped: {}", drops);
391 println!(" Leaked: {}", allocs - drops);
392
393 if allocs == drops {
394 println!("\n✅ Perfect! All allocated memory was freed!");
395 } else {
396 println!("\n❌ Memory leak detected!");
397 }
398
399 // ============================================================================
400 // TEST 8: Arc/Rc Compatibility
401 // ============================================================================
402 println!("\n═══════════════════════════════════════════════════════════════");
403 println!("Test 8: Arc/Rc compatibility - shared ownership works");
404 println!("═══════════════════════════════════════════════════════════════\n");
405
406 {
407 use std::sync::Arc;
408
409 #[derive(Keypaths)]
410 struct SharedData {
411 id: u32,
412 value: Arc<String>, // Shared ownership
413 }
414
415 let shared_string = Arc::new("Shared Value".to_string());
416 println!(" Arc strong count: {}", Arc::strong_count(&shared_string));
417
418 let data = vec![
419 SharedData { id: 1, value: Arc::clone(&shared_string) },
420 SharedData { id: 2, value: Arc::clone(&shared_string) },
421 ];
422
423 println!(" Arc strong count after creating data: {}", Arc::strong_count(&shared_string));
424
425 {
426 let query = Query::new(&data)
427 .where_(SharedData::id_r(), |&id| id > 0);
428 let results = query.all();
429 println!(" Found {} items", results.len());
430 println!(" Arc strong count during query: {}", Arc::strong_count(&shared_string));
431 }
432
433 println!(" Arc strong count after query: {}", Arc::strong_count(&shared_string));
434 }
435
436 println!(" ✅ Arc reference counting works correctly!\n");
437
438 // ============================================================================
439 // TEST 9: Large Data Without Clone - Zero Copy
440 // ============================================================================
441 println!("═══════════════════════════════════════════════════════════════");
442 println!("Test 9: Large data without Clone - verify zero-copy");
443 println!("═══════════════════════════════════════════════════════════════\n");
444
445 #[derive(Keypaths)] // NO Clone!
446 struct LargeRecord {
447 id: u32,
448 // Simulate 1MB of data that we DON'T want to clone
449 huge_data: Vec<u8>,
450 }
451
452 {
453 println!(" Creating 10 records (1MB each = 10MB total)...");
454 let large_records: Vec<LargeRecord> = (0..10)
455 .map(|i| LargeRecord {
456 id: i,
457 huge_data: vec![i as u8; 1_000_000], // 1MB each
458 })
459 .collect();
460
461 println!(" Total memory: ~10MB");
462
463 {
464 println!("\n Running query without Clone...");
465 let query = Query::new(&large_records)
466 .where_(LargeRecord::id_r(), |&id| id < 5);
467 let results = query.all(); // Vec<&LargeRecord> - NO CLONING!
468
469 println!(" Found {} records", results.len());
470 println!(" Memory copied: 0 bytes (just references)");
471 println!(" ✅ Zero-copy achieved!");
472 }
473
474 println!("\n Query dropped - no memory freed (no cloning happened)");
475 }
476
477 println!(" Records dropped - 10MB freed\n");
478
479 // ============================================================================
480 // TEST 10: Lifetime Safety
481 // ============================================================================
482 println!("═══════════════════════════════════════════════════════════════");
483 println!("Test 10: Lifetime safety - compiler prevents dangling refs");
484 println!("═══════════════════════════════════════════════════════════════\n");
485
486 println!(" The following code WILL NOT COMPILE (by design):\n");
487 println!(" ```rust");
488 println!(" let query;");
489 println!(" {{");
490 println!(" let data = vec![...];");
491 println!(" query = Query::new(&data); // data borrowed here");
492 println!(" }} // data dropped");
493 println!(" let results = query.all(); // ❌ ERROR: data doesn't live long enough");
494 println!(" ```\n");
495 println!(" ✅ Rust's borrow checker prevents use-after-free!");
496 println!(" ✅ 'static bound + lifetimes = memory safety guaranteed!\n");
497
498 // ============================================================================
499 // Summary
500 // ============================================================================
501 println!("═══════════════════════════════════════════════════════════════");
502 println!("Summary: Memory Safety Guarantees");
503 println!("═══════════════════════════════════════════════════════════════\n");
504
505 let (total_allocs, total_drops) = get_stats();
506 let leaked = total_allocs.saturating_sub(total_drops);
507
508 println!("Overall Statistics:");
509 println!(" Total allocations: {}", total_allocs);
510 println!(" Total drops: {}", total_drops);
511 println!(" Memory leaks: {}", leaked);
512
513 if leaked == 0 {
514 println!("\n🎉 VERIFIED: Zero memory leaks!\n");
515 } else {
516 println!("\n⚠️ WARNING: Potential memory leak detected!\n");
517 }
518
519 println!("Guarantees Verified:");
520 println!(" ✅ 'static doesn't cause data to live forever");
521 println!(" ✅ All allocated memory is properly freed");
522 println!(" ✅ No memory leaks from queries");
523 println!(" ✅ Query only holds references, not ownership");
524 println!(" ✅ Rust's borrow checker prevents dangling references");
525 println!(" ✅ RAII ensures proper cleanup");
526 println!(" ✅ Zero-copy operations don't allocate");
527 println!(" ✅ Clone operations are explicit and controlled\n");
528
529 println!("Performance Benefits:");
530 println!(" ✅ Filtering: 0 bytes copied (v0.2.0) vs 10MB (v0.1.0)");
531 println!(" ✅ Counting: 0 bytes copied");
532 println!(" ✅ Aggregations: 0 bytes copied");
533 println!(" ✅ Only ordering/grouping clone when needed\n");
534
535 println!("Safety Guarantees:");
536 println!(" ✅ Compile-time prevention of dangling references");
537 println!(" ✅ No use-after-free possible");
538 println!(" ✅ No double-free possible");
539 println!(" ✅ Automatic cleanup via RAII\n");
540
541 println!("✓ All memory safety tests PASSED!\n");
542}Sourcepub fn group_by<F>(&self, path: KeyPaths<T, F>) -> HashMap<F, Vec<T>>
pub fn group_by<F>(&self, path: KeyPaths<T, F>) -> HashMap<F, Vec<T>>
Groups results by a field value.
Note: This method requires T: Clone as it creates owned copies in groups.
§Arguments
path- The key-path to the field to group by
§Example
let by_category = query.group_by(Product::category_r());Examples found in repository?
30fn main() {
31 println!("Testing documentation examples...\n");
32
33 // Example from README - Quick Start
34 println!("Test 1: README Quick Start Example");
35 {
36 let products = vec![
37 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
38 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
39 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
40 ];
41
42 let affordable_query = Query::new(&products)
43 .where_(Product::category_r(), |cat| cat == "Electronics")
44 .where_(Product::price_r(), |&price| price < 100.0);
45 let affordable_electronics = affordable_query.all();
46
47 println!(" Found {} affordable electronics ✅", affordable_electronics.len());
48 }
49
50 // Example from README - Filtering
51 println!("\nTest 2: Filtering Example");
52 {
53 let products = vec![
54 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
55 ];
56
57 let electronics_query = Query::new(&products)
58 .where_(Product::category_r(), |cat| cat == "Electronics");
59 let electronics = electronics_query.all();
60
61 println!(" Found {} electronics ✅", electronics.len());
62 }
63
64 // Example from README - Selecting
65 println!("\nTest 3: Selecting Fields Example");
66 {
67 let products = vec![
68 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
69 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
70 ];
71
72 let names: Vec<String> = Query::new(&products)
73 .select(Product::name_r());
74
75 println!(" Selected {} names ✅", names.len());
76 }
77
78 // Example from README - Ordering
79 println!("\nTest 4: Ordering Example");
80 {
81 let products = vec![
82 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
83 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
84 ];
85
86 let by_price = Query::new(&products).order_by_float(Product::price_r());
87 println!(" Ordered {} products ✅", by_price.len());
88 }
89
90 // Example from README - Aggregations
91 println!("\nTest 5: Aggregations Example");
92 {
93 let products = vec![
94 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
95 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
96 ];
97
98 let electronics_query = Query::new(&products)
99 .where_(Product::category_r(), |cat| cat == "Electronics");
100
101 let count = electronics_query.count();
102 let total_value: f64 = electronics_query.sum(Product::price_r());
103 let avg_price = electronics_query.avg(Product::price_r()).unwrap_or(0.0);
104
105 println!(" Count: {}, Total: ${:.2}, Avg: ${:.2} ✅", count, total_value, avg_price);
106 }
107
108 // Example from README - Grouping
109 println!("\nTest 6: Grouping Example");
110 {
111 let products = vec![
112 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
113 Product { id: 2, name: "Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.0 },
114 Product { id: 3, name: "Desk".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 10, rating: 4.8 },
115 ];
116
117 let by_category = Query::new(&products).group_by(Product::category_r());
118 println!(" Grouped into {} categories ✅", by_category.len());
119 }
120
121 // Example from README - Pagination
122 println!("\nTest 7: Pagination Example");
123 {
124 let products = vec![
125 Product { id: 1, name: "P1".to_string(), price: 10.0, category: "A".to_string(), stock: 1, rating: 4.0 },
126 Product { id: 2, name: "P2".to_string(), price: 20.0, category: "A".to_string(), stock: 1, rating: 4.0 },
127 Product { id: 3, name: "P3".to_string(), price: 30.0, category: "A".to_string(), stock: 1, rating: 4.0 },
128 ];
129
130 let query = Query::new(&products);
131 let first_10 = query.limit(10);
132 let page_1 = query.skip(0).limit(10);
133
134 println!(" Limited to {} products ✅", first_10.len());
135 println!(" Page 1 has {} products ✅", page_1.len());
136 }
137
138 // Example from README - Join
139 println!("\nTest 8: Join Example");
140 {
141 let users = vec![
142 User { id: 1, name: "Alice".to_string() },
143 User { id: 2, name: "Bob".to_string() },
144 ];
145
146 let orders = vec![
147 Order { id: 101, user_id: 1, total: 99.99 },
148 Order { id: 102, user_id: 1, total: 149.99 },
149 ];
150
151 let user_orders = JoinQuery::new(&users, &orders).inner_join(
152 User::id_r(),
153 Order::user_id_r(),
154 |user, order| (user.name.clone(), order.total),
155 );
156
157 println!(" Joined {} user-order pairs ✅", user_orders.len());
158 }
159
160 // Example from SQL_COMPARISON - SELECT with WHERE
161 println!("\nTest 9: SQL Comparison - SELECT with WHERE");
162 {
163 #[derive(Clone, Keypaths)]
164 struct Employee {
165 department: String,
166 }
167
168 let employees = vec![
169 Employee { department: "Engineering".to_string() },
170 Employee { department: "Sales".to_string() },
171 ];
172
173 let engineering_query = Query::new(&employees)
174 .where_(Employee::department_r(), |dept| dept == "Engineering");
175 let engineering = engineering_query.all();
176
177 println!(" Found {} engineering employees ✅", engineering.len());
178 }
179
180 // Example from USAGE.md - Complex Filtering
181 println!("\nTest 10: USAGE - Complex Filtering");
182 {
183 let products = vec![
184 Product { id: 1, name: "Laptop".to_string(), price: 999.99, category: "Electronics".to_string(), stock: 15, rating: 4.5 },
185 ];
186
187 let results_query = Query::new(&products)
188 .where_(Product::category_r(), |cat| cat == "Electronics")
189 .where_(Product::price_r(), |&price| price >= 100.0 && price <= 500.0)
190 .where_(Product::stock_r(), |&stock| stock > 10);
191 let results = results_query.order_by_float(Product::price_r());
192
193 println!(" Filtered {} products ✅", results.len());
194 }
195
196 println!("\n✅ All documentation examples compile and run successfully!");
197}More examples
110fn main() {
111 println!("=== Advanced Query Builder Demo ===\n");
112
113 let products = create_product_catalog();
114 println!("Total products in catalog: {}\n", products.len());
115
116 // Query 1: Select all product names
117 println!("--- Query 1: Select All Product Names ---");
118 let names = Query::new(&products).select(Product::name_r());
119 println!("Product names ({}):", names.len());
120 for name in &names {
121 println!(" • {}", name);
122 }
123
124 // Query 2: Order by price (ascending)
125 println!("\n--- Query 2: Products Ordered by Price (Ascending) ---");
126 let ordered = Query::new(&products).order_by_float(Product::price_r());
127 for product in ordered.iter().take(5) {
128 println!(" • {} - ${:.2}", product.name, product.price);
129 }
130
131 // Query 3: Order by rating (descending)
132 println!("\n--- Query 3: Top-Rated Products (Descending) ---");
133 let top_rated = Query::new(&products).order_by_float_desc(Product::rating_r());
134 for product in top_rated.iter().take(5) {
135 println!(" • {} - Rating: {:.1}", product.name, product.rating);
136 }
137
138 // Query 4: Group by category
139 println!("\n--- Query 4: Products Grouped by Category ---");
140 let by_category = Query::new(&products).group_by(Product::category_r());
141 for (category, items) in &by_category {
142 println!(" {}: {} products", category, items.len());
143 for item in items {
144 println!(" - {} (${:.2})", item.name, item.price);
145 }
146 }
147
148 // Query 5: Aggregations - Electronics statistics
149 println!("\n--- Query 5: Electronics Category Statistics ---");
150 let electronics_query = Query::new(&products)
151 .where_(Product::category_r(), |cat| cat == "Electronics");
152
153 println!(" Count: {}", electronics_query.count());
154 println!(" Total Value: ${:.2}", electronics_query.sum(Product::price_r()));
155 println!(" Average Price: ${:.2}", electronics_query.avg(Product::price_r()).unwrap_or(0.0));
156 println!(" Min Price: ${:.2}", electronics_query.min_float(Product::price_r()).unwrap_or(0.0));
157 println!(" Max Price: ${:.2}", electronics_query.max_float(Product::price_r()).unwrap_or(0.0));
158 println!(" Total Stock: {}", electronics_query.sum(Product::stock_r()));
159
160 // Query 6: Complex filtering with ordering
161 println!("\n--- Query 6: Electronics Under $200, Ordered by Rating ---");
162 let affordable_electronics = Query::new(&products)
163 .where_(Product::category_r(), |cat| cat == "Electronics")
164 .where_(Product::price_r(), |&price| price < 200.0)
165 .order_by_float_desc(Product::rating_r());
166
167 for product in &affordable_electronics {
168 println!(
169 " • {} - ${:.2} - Rating: {:.1}",
170 product.name, product.price, product.rating
171 );
172 }
173
174 // Query 7: Limit results
175 println!("\n--- Query 7: First 3 Products ---");
176 let query7 = Query::new(&products);
177 let first_three = query7.limit(3);
178 for product in &first_three {
179 println!(" • {} (ID: {})", product.name, product.id);
180 }
181
182 // Query 8: Pagination
183 println!("\n--- Query 8: Pagination (Page 2, 3 items per page) ---");
184 let query8 = Query::new(&products);
185 let page_2 = query8.skip(3).limit(3);
186 for product in &page_2 {
187 println!(" • {} (ID: {})", product.name, product.id);
188 }
189
190 // Query 9: First matching item
191 println!("\n--- Query 9: Find First Product Over $1000 ---");
192 let query9 = Query::new(&products)
193 .where_(Product::price_r(), |&price| price > 1000.0);
194 let expensive = query9.first();
195
196 if let Some(product) = expensive {
197 println!(" Found: {} - ${:.2}", product.name, product.price);
198 } else {
199 println!(" No products found over $1000");
200 }
201
202 // Query 10: Check existence
203 println!("\n--- Query 10: Check if Any Furniture Exists ---");
204 let has_furniture = Query::new(&products)
205 .where_(Product::category_r(), |cat| cat == "Furniture")
206 .exists();
207 println!(" Furniture available: {}", has_furniture);
208
209 // Query 11: Multiple aggregations by group
210 println!("\n--- Query 11: Category Statistics ---");
211 let grouped = Query::new(&products).group_by(Product::category_r());
212
213 for (category, items) in &grouped {
214 let cat_query = Query::new(items);
215 println!("\n {} Statistics:", category);
216 println!(" Products: {}", items.len());
217 println!(" Total Value: ${:.2}", cat_query.sum(Product::price_r()));
218 println!(" Avg Price: ${:.2}", cat_query.avg(Product::price_r()).unwrap_or(0.0));
219 println!(" Total Stock: {}", cat_query.sum(Product::stock_r()));
220 println!(" Avg Rating: {:.2}", cat_query.avg(Product::rating_r()).unwrap_or(0.0));
221 }
222
223 // Query 12: Complex multi-stage query
224 println!("\n--- Query 12: Top 3 Highly-Rated Products (Rating > 4.5) by Price ---");
225 let top_products = Query::new(&products)
226 .where_(Product::rating_r(), |&rating| rating > 4.5)
227 .order_by_float_desc(Product::price_r());
228
229 for (i, product) in top_products.iter().take(3).enumerate() {
230 println!(
231 " {}. {} - ${:.2} - Rating: {:.1}",
232 i + 1,
233 product.name,
234 product.price,
235 product.rating
236 );
237 }
238
239 // Query 13: Select multiple fields (simulated with tuples)
240 println!("\n--- Query 13: Select Name and Price for Electronics ---");
241 let query13 = Query::new(&products)
242 .where_(Product::category_r(), |cat| cat == "Electronics");
243 let electronics = query13.all();
244
245 for product in electronics {
246 println!(" • {} - ${:.2}", product.name, product.price);
247 }
248
249 // Query 14: Stock analysis
250 println!("\n--- Query 14: Low Stock Alert (Stock < 20) ---");
251 let low_stock = Query::new(&products)
252 .where_(Product::stock_r(), |&stock| stock < 20)
253 .order_by(Product::stock_r());
254
255 for product in &low_stock {
256 println!(" ⚠️ {} - Only {} in stock", product.name, product.stock);
257 }
258
259 // Query 15: Price range query with multiple conditions
260 println!("\n--- Query 15: Mid-Range Products ($50-$300) with Good Ratings (>4.5) ---");
261 let mid_range = Query::new(&products)
262 .where_(Product::price_r(), |&price| price >= 50.0 && price <= 300.0)
263 .where_(Product::rating_r(), |&rating| rating > 4.5)
264 .order_by_float(Product::price_r());
265
266 for product in &mid_range {
267 println!(
268 " • {} - ${:.2} - Rating: {:.1} - Stock: {}",
269 product.name, product.price, product.rating, product.stock
270 );
271 }
272
273 // Query 16: Revenue calculation
274 println!("\n--- Query 16: Potential Revenue by Category ---");
275 let by_category = Query::new(&products).group_by(Product::category_r());
276
277 for (category, items) in &by_category {
278 let revenue: f64 = items.iter().map(|p| p.price * p.stock as f64).sum();
279 println!(" {}: ${:.2}", category, revenue);
280 }
281
282 println!("\n✓ Advanced query builder demo complete!");
283}33fn main() {
34 let employees = create_test_data();
35
36 println!("\n╔════════════════════════════════════════════════════════════════╗");
37 println!("║ SQL Equivalence Verification Tests ║");
38 println!("╚════════════════════════════════════════════════════════════════╝\n");
39
40 // TEST 1: ORDER BY maintains exact SQL ordering (DESC)
41 println!("Test 1: ORDER BY DESC - Exact ordering");
42 println!("SQL: SELECT * FROM employees ORDER BY salary DESC;");
43
44 let ordered = Query::new(&employees).order_by_float_desc(Employee::salary_r());
45 let expected_order = vec![105000.0, 95000.0, 87000.0, 82000.0, 75000.0, 71000.0];
46 let actual_order: Vec<f64> = ordered.iter().map(|e| e.salary).collect();
47
48 let test1_pass = expected_order == actual_order;
49 print_test("ORDER BY salary DESC produces correct order", test1_pass);
50 if !test1_pass {
51 println!(" Expected: {:?}", expected_order);
52 println!(" Got: {:?}", actual_order);
53 }
54
55 // TEST 2: ORDER BY maintains exact SQL ordering (ASC)
56 println!("\nTest 2: ORDER BY ASC - Exact ordering");
57 println!("SQL: SELECT * FROM employees ORDER BY salary ASC;");
58
59 let ordered_asc = Query::new(&employees).order_by_float(Employee::salary_r());
60 let expected_asc = vec![71000.0, 75000.0, 82000.0, 87000.0, 95000.0, 105000.0];
61 let actual_asc: Vec<f64> = ordered_asc.iter().map(|e| e.salary).collect();
62
63 let test2_pass = expected_asc == actual_asc;
64 print_test("ORDER BY salary ASC produces correct order", test2_pass);
65 if !test2_pass {
66 println!(" Expected: {:?}", expected_asc);
67 println!(" Got: {:?}", actual_asc);
68 }
69
70 // TEST 3: String ordering (alphabetical)
71 println!("\nTest 3: ORDER BY name (alphabetical)");
72 println!("SQL: SELECT name FROM employees ORDER BY name;");
73
74 let ordered_names = Query::new(&employees).order_by(Employee::name_r());
75 let expected_names = vec!["Alice Cooper", "Alice Johnson", "Bob Smith", "Carol White", "David Brown", "Eve Davis"];
76 let actual_names: Vec<&str> = ordered_names.iter().map(|e| e.name.as_str()).collect();
77
78 let test3_pass = expected_names == actual_names;
79 print_test("ORDER BY name produces correct alphabetical order", test3_pass);
80 if !test3_pass {
81 println!(" Expected: {:?}", expected_names);
82 println!(" Got: {:?}", actual_names);
83 }
84
85 // TEST 4: LIKE equivalent - starts with
86 println!("\nTest 4: LIKE 'Alice%' equivalent");
87 println!("SQL: SELECT * FROM employees WHERE name LIKE 'Alice%';");
88
89 let like_alice_query = Query::new(&employees)
90 .where_(Employee::name_r(), |name| name.starts_with("Alice"));
91 let like_alice = like_alice_query.all();
92
93 let test4_pass = like_alice.len() == 2
94 && like_alice.iter().all(|e| e.name.starts_with("Alice"));
95 print_test("LIKE 'Alice%' (starts_with) works correctly", test4_pass);
96 if test4_pass {
97 for emp in &like_alice {
98 println!(" Found: {}", emp.name);
99 }
100 }
101
102 // TEST 5: LIKE equivalent - ends with
103 println!("\nTest 5: LIKE '%son' equivalent");
104 println!("SQL: SELECT * FROM employees WHERE name LIKE '%son';");
105
106 let like_son_query = Query::new(&employees)
107 .where_(Employee::name_r(), |name| name.ends_with("son"));
108 let like_son = like_son_query.all();
109
110 let test5_pass = like_son.len() == 1 && like_son[0].name == "Alice Johnson";
111 print_test("LIKE '%son' (ends_with) works correctly", test5_pass);
112 if test5_pass {
113 for emp in &like_son {
114 println!(" Found: {}", emp.name);
115 }
116 }
117
118 // TEST 6: LIKE equivalent - contains
119 println!("\nTest 6: LIKE '%mit%' equivalent");
120 println!("SQL: SELECT * FROM employees WHERE name LIKE '%mit%';");
121
122 let like_mit_query = Query::new(&employees)
123 .where_(Employee::name_r(), |name| name.contains("mit"));
124 let like_mit = like_mit_query.all();
125
126 let test6_pass = like_mit.len() == 1 && like_mit[0].name == "Bob Smith";
127 print_test("LIKE '%mit%' (contains) works correctly", test6_pass);
128 if test6_pass {
129 for emp in &like_mit {
130 println!(" Found: {}", emp.name);
131 }
132 }
133
134 // TEST 7: IN clause equivalent
135 println!("\nTest 7: IN clause equivalent");
136 println!("SQL: SELECT * FROM employees WHERE department IN ('Engineering', 'Sales');");
137
138 let in_depts_query = Query::new(&employees)
139 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales");
140 let in_depts = in_depts_query.all();
141
142 let test7_pass = in_depts.len() == 5 // 3 Engineering + 2 Sales
143 && in_depts.iter().all(|e| e.department == "Engineering" || e.department == "Sales");
144 print_test("IN clause works correctly", test7_pass);
145 println!(" Found {} employees in Engineering or Sales", in_depts.len());
146
147 // TEST 8: BETWEEN equivalent
148 println!("\nTest 8: BETWEEN clause equivalent");
149 println!("SQL: SELECT * FROM employees WHERE salary BETWEEN 75000 AND 90000;");
150
151 let between_query = Query::new(&employees)
152 .where_(Employee::salary_r(), |&sal| sal >= 75000.0 && sal <= 90000.0);
153 let between = between_query.all();
154
155 let test8_pass = between.len() == 3;
156 print_test("BETWEEN clause works correctly", test8_pass);
157 println!(" Found {} employees with salary between 75K-90K", between.len());
158
159 // TEST 9: COUNT with WHERE
160 println!("\nTest 9: COUNT with WHERE");
161 println!("SQL: SELECT COUNT(*) FROM employees WHERE department = 'Engineering';");
162
163 let count_eng = Query::new(&employees)
164 .where_(Employee::department_r(), |dept| dept == "Engineering")
165 .count();
166
167 let test9_pass = count_eng == 3;
168 print_test("COUNT with WHERE produces correct result", test9_pass);
169 println!(" Count: {} (expected 3)", count_eng);
170
171 // TEST 10: AVG produces exact result
172 println!("\nTest 10: AVG aggregation accuracy");
173 println!("SQL: SELECT AVG(salary) FROM employees WHERE department = 'Engineering';");
174
175 let avg_sal = Query::new(&employees)
176 .where_(Employee::department_r(), |dept| dept == "Engineering")
177 .avg(Employee::salary_r())
178 .unwrap_or(0.0);
179
180 let expected_avg = (95000.0 + 87000.0 + 105000.0) / 3.0;
181 let test10_pass = (avg_sal - expected_avg).abs() < 0.01;
182 print_test("AVG produces mathematically correct result", test10_pass);
183 println!(" Average: ${:.2} (expected ${:.2})", avg_sal, expected_avg);
184
185 // TEST 11: MIN and MAX
186 println!("\nTest 11: MIN and MAX aggregations");
187 println!("SQL: SELECT MIN(salary), MAX(salary) FROM employees;");
188
189 let min_sal = Query::new(&employees).min_float(Employee::salary_r()).unwrap_or(0.0);
190 let max_sal = Query::new(&employees).max_float(Employee::salary_r()).unwrap_or(0.0);
191
192 let test11_pass = min_sal == 71000.0 && max_sal == 105000.0;
193 print_test("MIN and MAX produce correct results", test11_pass);
194 println!(" MIN: ${:.2}, MAX: ${:.2}", min_sal, max_sal);
195
196 // TEST 12: Complex WHERE with AND/OR
197 println!("\nTest 12: Complex WHERE (AND + OR)");
198 println!("SQL: SELECT * FROM employees WHERE (department = 'Engineering' OR department = 'Sales') AND salary > 80000;");
199
200 let complex_query = Query::new(&employees)
201 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
202 .where_(Employee::salary_r(), |&sal| sal > 80000.0);
203 let complex = complex_query.all();
204
205 let test12_pass = complex.len() == 4; // Alice J ($95k), Bob ($87k), David ($82k), Alice C ($105k)
206 print_test("Complex WHERE clause works correctly", test12_pass);
207 println!(" Found {} employees", complex.len());
208
209 // TEST 13: Case-sensitive string comparison (SQL default)
210 println!("\nTest 13: Case-sensitive comparison (like SQL)");
211 println!("SQL: SELECT * FROM employees WHERE department = 'engineering'; -- should find 0");
212
213 let case_sensitive = Query::new(&employees)
214 .where_(Employee::department_r(), |dept| dept == "engineering") // lowercase
215 .count();
216
217 let test13_pass = case_sensitive == 0;
218 print_test("Case-sensitive comparison (SQL default)", test13_pass);
219 println!(" Found {} with lowercase 'engineering' (expected 0)", case_sensitive);
220
221 // TEST 14: Case-insensitive LIKE equivalent
222 println!("\nTest 14: Case-insensitive LIKE (ILIKE equivalent)");
223 println!("SQL: SELECT * FROM employees WHERE LOWER(name) LIKE '%alice%';");
224
225 let ilike_query = Query::new(&employees)
226 .where_(Employee::name_r(), |name| name.to_lowercase().contains("alice"));
227 let ilike = ilike_query.all();
228
229 let test14_pass = ilike.len() == 2;
230 print_test("Case-insensitive LIKE works correctly", test14_pass);
231 println!(" Found {} employees with 'alice' (case-insensitive)", ilike.len());
232
233 // TEST 15: LIMIT produces exact subset
234 println!("\nTest 15: LIMIT clause");
235 println!("SQL: SELECT * FROM employees ORDER BY salary DESC LIMIT 3;");
236
237 let limited = Query::new(&employees)
238 .order_by_float_desc(Employee::salary_r())
239 .into_iter()
240 .take(3)
241 .collect::<Vec<_>>();
242
243 let test15_pass = limited.len() == 3
244 && limited[0].salary == 105000.0
245 && limited[1].salary == 95000.0
246 && limited[2].salary == 87000.0;
247 print_test("LIMIT returns correct top-N results", test15_pass);
248 println!(" Top 3 salaries: ${:.0}, ${:.0}, ${:.0}",
249 limited[0].salary, limited[1].salary, limited[2].salary);
250
251 // TEST 16: GROUP BY produces correct groups
252 println!("\nTest 16: GROUP BY");
253 println!("SQL: SELECT department, COUNT(*) FROM employees GROUP BY department;");
254
255 let grouped = Query::new(&employees).group_by(Employee::department_r());
256 let eng_count = grouped.get("Engineering").map(|v| v.len()).unwrap_or(0);
257 let sales_count = grouped.get("Sales").map(|v| v.len()).unwrap_or(0);
258 let marketing_count = grouped.get("Marketing").map(|v| v.len()).unwrap_or(0);
259
260 let test16_pass = eng_count == 3 && sales_count == 2 && marketing_count == 1;
261 print_test("GROUP BY produces correct counts", test16_pass);
262 println!(" Engineering: {}, Sales: {}, Marketing: {}", eng_count, sales_count, marketing_count);
263
264 // TEST 17: Email pattern matching (regex-like)
265 println!("\nTest 17: Email domain filtering (LIKE '%@example.com')");
266 println!("SQL: SELECT * FROM employees WHERE email LIKE '%@example.com';");
267
268 let example_emails = Query::new(&employees)
269 .where_(Employee::email_r(), |email| email.ends_with("@example.com"))
270 .count();
271
272 let test17_pass = example_emails == 6; // All employees have @example.com emails
273 print_test("Email pattern matching works correctly", test17_pass);
274 println!(" Found {} employees with @example.com emails", example_emails);
275
276 // Summary
277 println!("\n╔════════════════════════════════════════════════════════════════╗");
278 println!("║ Test Summary ║");
279 println!("╚════════════════════════════════════════════════════════════════╝\n");
280
281 let tests = vec![
282 ("ORDER BY DESC", test1_pass),
283 ("ORDER BY ASC", test2_pass),
284 ("ORDER BY name", test3_pass),
285 ("LIKE 'prefix%'", test4_pass),
286 ("LIKE '%suffix'", test5_pass),
287 ("LIKE '%contains%'", test6_pass),
288 ("IN clause", test7_pass),
289 ("BETWEEN clause", test8_pass),
290 ("COUNT", test9_pass),
291 ("AVG accuracy", test10_pass),
292 ("MIN/MAX", test11_pass),
293 ("Complex WHERE", test12_pass),
294 ("Case-sensitive", test13_pass),
295 ("Case-insensitive", test14_pass),
296 ("LIMIT", test15_pass),
297 ("GROUP BY", test16_pass),
298 ("Email patterns", test17_pass),
299 ];
300
301 let passed = tests.iter().filter(|(_, p)| *p).count();
302 let total = tests.len();
303
304 println!("Results: {}/{} tests passed", passed, total);
305
306 if passed == total {
307 println!("\n🎉 All tests PASSED! Rust Query Builder produces exact SQL-equivalent results!");
308 println!("\n✅ Verified:");
309 println!(" • Exact ordering (ASC/DESC)");
310 println!(" • LIKE operations (starts_with, ends_with, contains)");
311 println!(" • IN clause (OR conditions)");
312 println!(" • BETWEEN clause");
313 println!(" • Aggregations (COUNT, AVG, MIN, MAX)");
314 println!(" • Complex WHERE conditions");
315 println!(" • Case sensitivity");
316 println!(" • LIMIT clause");
317 println!(" • GROUP BY");
318 println!(" • Pattern matching");
319 } else {
320 println!("\n⚠️ {} test(s) failed. See details above.", total - passed);
321 }
322}84fn main() {
85 let employees = create_employees();
86 let departments = create_departments();
87 let projects = create_projects();
88
89 println!("\n╔════════════════════════════════════════════════════════════════════════╗");
90 println!("║ SQL vs Rust Query Builder Comparison ║");
91 println!("║ Demonstrating equivalent operations ║");
92 println!("╚════════════════════════════════════════════════════════════════════════╝");
93
94 // ============================================================================
95 // EXAMPLE 1: Simple SELECT with WHERE
96 // ============================================================================
97 print_separator("Example 1: SELECT with WHERE clause");
98 print_query(
99 "SELECT * FROM employees WHERE department = 'Engineering';",
100 "Filter employees by department"
101 );
102
103 let eng_query = Query::new(&employees)
104 .where_(Employee::department_r(), |dept| dept == "Engineering");
105 let engineering_employees = eng_query.all();
106
107 for emp in &engineering_employees {
108 println!(" ID: {}, Name: {}, Salary: ${:.2}", emp.id, emp.name, emp.salary);
109 }
110 println!("\nRust Query Builder:");
111 println!("Query::new(&employees)");
112 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\")");
113 println!(" .all()");
114 println!("✓ Found {} employees", engineering_employees.len());
115
116 // ============================================================================
117 // EXAMPLE 2: SELECT specific columns
118 // ============================================================================
119 print_separator("Example 2: SELECT specific columns (Projection)");
120 print_query(
121 "SELECT name FROM employees WHERE salary > 80000;",
122 "Get names of high-earning employees"
123 );
124
125 let high_earners = Query::new(&employees)
126 .where_(Employee::salary_r(), |&salary| salary > 80000.0)
127 .select(Employee::name_r());
128
129 for name in &high_earners {
130 println!(" {}", name);
131 }
132 println!("\nRust Query Builder:");
133 println!("Query::new(&employees)");
134 println!(" .where_(Employee::salary_r(), |&salary| salary > 80000.0)");
135 println!(" .select(Employee::name_r())");
136 println!("✓ Found {} employees", high_earners.len());
137
138 // ============================================================================
139 // EXAMPLE 3: COUNT
140 // ============================================================================
141 print_separator("Example 3: COUNT aggregation");
142 print_query(
143 "SELECT COUNT(*) FROM employees WHERE age < 30;",
144 "Count young employees"
145 );
146
147 let young_count = Query::new(&employees)
148 .where_(Employee::age_r(), |&age| age < 30)
149 .count();
150
151 println!(" Count: {}", young_count);
152 println!("\nRust Query Builder:");
153 println!("Query::new(&employees)");
154 println!(" .where_(Employee::age_r(), |&age| age < 30)");
155 println!(" .count()");
156 println!("✓ Result: {}", young_count);
157
158 // ============================================================================
159 // EXAMPLE 4: SUM, AVG, MIN, MAX
160 // ============================================================================
161 print_separator("Example 4: Aggregate functions (SUM, AVG, MIN, MAX)");
162 print_query(
163 "SELECT \n\
164 SUM(salary) as total_salary,\n\
165 AVG(salary) as avg_salary,\n\
166 MIN(salary) as min_salary,\n\
167 MAX(salary) as max_salary\n\
168 FROM employees WHERE department = 'Engineering';",
169 "Engineering department salary statistics"
170 );
171
172 let eng_query = Query::new(&employees)
173 .where_(Employee::department_r(), |dept| dept == "Engineering");
174
175 let total = eng_query.sum(Employee::salary_r());
176 let avg = eng_query.avg(Employee::salary_r()).unwrap_or(0.0);
177 let min = eng_query.min_float(Employee::salary_r()).unwrap_or(0.0);
178 let max = eng_query.max_float(Employee::salary_r()).unwrap_or(0.0);
179
180 println!(" Total Salary: ${:.2}", total);
181 println!(" Avg Salary: ${:.2}", avg);
182 println!(" Min Salary: ${:.2}", min);
183 println!(" Max Salary: ${:.2}", max);
184
185 println!("\nRust Query Builder:");
186 println!("let query = Query::new(&employees)");
187 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\");");
188 println!("query.sum(Employee::salary_r()) // ${:.2}", total);
189 println!("query.avg(Employee::salary_r()) // ${:.2}", avg);
190 println!("query.min_float(Employee::salary_r()) // ${:.2}", min);
191 println!("query.max_float(Employee::salary_r()) // ${:.2}", max);
192
193 // ============================================================================
194 // EXAMPLE 5: GROUP BY with aggregation
195 // ============================================================================
196 print_separator("Example 5: GROUP BY with aggregation");
197 print_query(
198 "SELECT \n\
199 department,\n\
200 COUNT(*) as emp_count,\n\
201 AVG(salary) as avg_salary\n\
202 FROM employees\n\
203 GROUP BY department;",
204 "Statistics by department"
205 );
206
207 let by_dept = Query::new(&employees).group_by(Employee::department_r());
208
209 for (dept, emps) in &by_dept {
210 let dept_query = Query::new(emps);
211 let count = emps.len();
212 let avg_sal = dept_query.avg(Employee::salary_r()).unwrap_or(0.0);
213 println!(" {}: {} employees, avg salary ${:.2}", dept, count, avg_sal);
214 }
215
216 println!("\nRust Query Builder:");
217 println!("let by_dept = Query::new(&employees).group_by(Employee::department_r());");
218 println!("for (dept, emps) in &by_dept {{");
219 println!(" let dept_query = Query::new(emps);");
220 println!(" dept_query.avg(Employee::salary_r())");
221 println!("}}");
222
223 // ============================================================================
224 // EXAMPLE 6: ORDER BY
225 // ============================================================================
226 print_separator("Example 6: ORDER BY");
227 print_query(
228 "SELECT name, salary FROM employees\n\
229 WHERE department = 'Sales'\n\
230 ORDER BY salary DESC;",
231 "Sales employees ordered by salary (descending)"
232 );
233
234 let sales_sorted = Query::new(&employees)
235 .where_(Employee::department_r(), |dept| dept == "Sales")
236 .order_by_float_desc(Employee::salary_r());
237
238 for emp in &sales_sorted {
239 println!(" {}: ${:.2}", emp.name, emp.salary);
240 }
241
242 println!("\nRust Query Builder:");
243 println!("Query::new(&employees)");
244 println!(" .where_(Employee::department_r(), |dept| dept == \"Sales\")");
245 println!(" .order_by_float_desc(Employee::salary_r())");
246
247 // ============================================================================
248 // EXAMPLE 7: Multiple WHERE conditions (AND)
249 // ============================================================================
250 print_separator("Example 7: Multiple WHERE conditions (AND)");
251 print_query(
252 "SELECT * FROM employees\n\
253 WHERE salary > 70000 AND age < 35;",
254 "High-earning young employees"
255 );
256
257 let filter_query = Query::new(&employees)
258 .where_(Employee::salary_r(), |&salary| salary > 70000.0)
259 .where_(Employee::age_r(), |&age| age < 35);
260 let filtered = filter_query.all();
261
262 for emp in &filtered {
263 println!(" {}: Age {}, Salary ${:.2}", emp.name, emp.age, emp.salary);
264 }
265
266 println!("\nRust Query Builder:");
267 println!("Query::new(&employees)");
268 println!(" .where_(Employee::salary_r(), |&salary| salary > 70000.0)");
269 println!(" .where_(Employee::age_r(), |&age| age < 35)");
270 println!(" .all()");
271 println!("✓ Found {} employees", filtered.len());
272
273 // ============================================================================
274 // EXAMPLE 8: LIMIT (TOP N)
275 // ============================================================================
276 print_separator("Example 8: LIMIT / TOP N");
277 print_query(
278 "SELECT TOP 3 name, salary FROM employees\n\
279 ORDER BY salary DESC;",
280 "Top 3 highest paid employees"
281 );
282
283 let top_earners = Query::new(&employees)
284 .order_by_float_desc(Employee::salary_r());
285
286 for (i, emp) in top_earners.iter().take(3).enumerate() {
287 println!(" {}. {}: ${:.2}", i + 1, emp.name, emp.salary);
288 }
289
290 println!("\nRust Query Builder:");
291 println!("Query::new(&employees)");
292 println!(" .order_by_float_desc(Employee::salary_r())");
293 println!(" .into_iter().take(3)");
294
295 // ============================================================================
296 // EXAMPLE 9: OFFSET and LIMIT (Pagination)
297 // ============================================================================
298 print_separator("Example 9: OFFSET and LIMIT (Pagination)");
299 print_query(
300 "SELECT name FROM employees\n\
301 ORDER BY name\n\
302 LIMIT 3 OFFSET 3;",
303 "Page 2 of employee names (3 per page)"
304 );
305
306 let page_2 = Query::new(&employees)
307 .order_by(Employee::name_r())
308 .into_iter()
309 .skip(3)
310 .take(3)
311 .collect::<Vec<_>>();
312
313 for emp in &page_2 {
314 println!(" {}", emp.name);
315 }
316
317 println!("\nRust Query Builder:");
318 println!("Query::new(&employees)");
319 println!(" .order_by(Employee::name_r())");
320 println!(" .into_iter().skip(3).take(3)");
321
322 // ============================================================================
323 // EXAMPLE 10: INNER JOIN
324 // ============================================================================
325 print_separator("Example 10: INNER JOIN");
326 print_query(
327 "SELECT e.name, d.name as dept_name, d.budget\n\
328 FROM employees e\n\
329 INNER JOIN departments d ON e.department = d.name;",
330 "Employees with their department info"
331 );
332
333 let emp_dept = JoinQuery::new(&employees, &departments).inner_join(
334 Employee::department_r(),
335 Department::name_r(),
336 |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget),
337 );
338
339 for (emp_name, dept_name, budget) in emp_dept.iter().take(5) {
340 println!(" {} works in {} (Budget: ${:.0})", emp_name, dept_name, budget);
341 }
342 println!(" ... (showing first 5)");
343
344 println!("\nRust Query Builder:");
345 println!("JoinQuery::new(&employees, &departments).inner_join(");
346 println!(" Employee::department_r(),");
347 println!(" Department::name_r(),");
348 println!(" |emp, dept| (emp.name.clone(), dept.name.clone(), dept.budget)");
349 println!(")");
350 println!("✓ Found {} matches", emp_dept.len());
351
352 // ============================================================================
353 // EXAMPLE 11: GROUP BY with HAVING equivalent
354 // ============================================================================
355 print_separator("Example 11: GROUP BY with filtering (HAVING equivalent)");
356 print_query(
357 "SELECT city, COUNT(*) as emp_count, AVG(salary) as avg_salary\n\
358 FROM employees\n\
359 GROUP BY city\n\
360 HAVING COUNT(*) > 1;",
361 "Cities with multiple employees"
362 );
363
364 let by_city = Query::new(&employees).group_by(Employee::city_r());
365 let mut city_stats: Vec<_> = by_city
366 .iter()
367 .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent
368 .map(|(city, emps)| {
369 let avg_sal = Query::new(emps).avg(Employee::salary_r()).unwrap_or(0.0);
370 (city.clone(), emps.len(), avg_sal)
371 })
372 .collect();
373
374 city_stats.sort_by(|a, b| b.1.cmp(&a.1)); // Sort by count
375
376 for (city, count, avg_sal) in &city_stats {
377 println!(" {}: {} employees, avg salary ${:.2}", city, count, avg_sal);
378 }
379
380 println!("\nRust Query Builder:");
381 println!("let by_city = Query::new(&employees).group_by(Employee::city_r());");
382 println!("by_city.iter()");
383 println!(" .filter(|(_, emps)| emps.len() > 1) // HAVING equivalent");
384 println!(" .map(|(city, emps)| {{");
385 println!(" let avg = Query::new(emps).avg(Employee::salary_r());");
386 println!(" (city, emps.len(), avg)");
387 println!(" }})");
388
389 // ============================================================================
390 // EXAMPLE 12: Complex query with multiple operations
391 // ============================================================================
392 print_separator("Example 12: Complex multi-operation query");
393 print_query(
394 "SELECT name, salary, age\n\
395 FROM employees\n\
396 WHERE department IN ('Engineering', 'Sales')\n\
397 AND salary BETWEEN 80000 AND 100000\n\
398 AND age >= 30\n\
399 ORDER BY salary DESC;",
400 "Experienced mid-to-senior level employees in core departments"
401 );
402
403 let complex_query = Query::new(&employees)
404 .where_(Employee::department_r(), |dept| dept == "Engineering" || dept == "Sales")
405 .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)
406 .where_(Employee::age_r(), |&age| age >= 30)
407 .order_by_float_desc(Employee::salary_r());
408
409 for emp in &complex_query {
410 println!(" {}: Age {}, {} dept, ${:.2}", emp.name, emp.age, emp.department, emp.salary);
411 }
412
413 println!("\nRust Query Builder:");
414 println!("Query::new(&employees)");
415 println!(" .where_(Employee::department_r(), |dept| dept == \"Engineering\" || dept == \"Sales\")");
416 println!(" .where_(Employee::salary_r(), |&sal| sal >= 80000.0 && sal <= 100000.0)");
417 println!(" .where_(Employee::age_r(), |&age| age >= 30)");
418 println!(" .order_by_float_desc(Employee::salary_r())");
419 println!("✓ Found {} employees", complex_query.len());
420
421 // ============================================================================
422 // EXAMPLE 13: Three-table JOIN
423 // ============================================================================
424 print_separator("Example 13: Three-table JOIN");
425 print_query(
426 "SELECT p.name as project, d.name as department, d.location\n\
427 FROM projects p\n\
428 INNER JOIN departments d ON p.department_id = d.id;",
429 "Projects with their department details"
430 );
431
432 let proj_dept = JoinQuery::new(&projects, &departments).inner_join(
433 Project::department_id_r(),
434 Department::id_r(),
435 |proj, dept| {
436 (proj.name.clone(), dept.name.clone(), dept.location.clone(), proj.budget)
437 },
438 );
439
440 for (proj_name, dept_name, location, budget) in &proj_dept {
441 println!(" {}: {} dept in {} (${:.0})", proj_name, dept_name, location, budget);
442 }
443
444 println!("\nRust Query Builder:");
445 println!("JoinQuery::new(&projects, &departments).inner_join(");
446 println!(" Project::department_id_r(),");
447 println!(" Department::id_r(),");
448 println!(" |proj, dept| (proj.name, dept.name, dept.location, proj.budget)");
449 println!(")");
450
451 // ============================================================================
452 // EXAMPLE 14: Subquery equivalent (using intermediate results)
453 // ============================================================================
454 print_separator("Example 14: Subquery equivalent");
455 print_query(
456 "SELECT * FROM employees\n\
457 WHERE salary > (SELECT AVG(salary) FROM employees);",
458 "Employees earning above average"
459 );
460
461 let avg_salary = Query::new(&employees)
462 .avg(Employee::salary_r())
463 .unwrap_or(0.0);
464
465 let above_avg_query = Query::new(&employees)
466 .where_(Employee::salary_r(), move |&sal| sal > avg_salary);
467 let above_avg = above_avg_query.all();
468
469 println!(" Average salary: ${:.2}", avg_salary);
470 for emp in &above_avg {
471 println!(" {}: ${:.2} ({:.1}% above average)",
472 emp.name, emp.salary, ((emp.salary - avg_salary) / avg_salary * 100.0));
473 }
474
475 println!("\nRust Query Builder:");
476 println!("let avg = Query::new(&employees).avg(Employee::salary_r()).unwrap_or(0.0);");
477 println!("Query::new(&employees)");
478 println!(" .where_(Employee::salary_r(), |&sal| sal > avg)");
479 println!(" .all()");
480 println!("✓ Found {} employees above average", above_avg.len());
481
482 // ============================================================================
483 // EXAMPLE 15: Advanced aggregation (revenue calculation)
484 // ============================================================================
485 print_separator("Example 15: Advanced aggregation");
486 print_query(
487 "SELECT \n\
488 d.name,\n\
489 d.budget as dept_budget,\n\
490 SUM(p.budget) as total_project_budget,\n\
491 (d.budget - SUM(p.budget)) as remaining_budget\n\
492 FROM departments d\n\
493 LEFT JOIN projects p ON d.id = p.department_id\n\
494 GROUP BY d.name, d.budget;",
495 "Department budget utilization"
496 );
497
498 // Join departments with projects
499 let dept_projects = JoinQuery::new(&departments, &projects).left_join(
500 Department::id_r(),
501 Project::department_id_r(),
502 |dept, proj| (dept.clone(), proj.map(|p| p.clone())),
503 );
504
505 // Aggregate by department
506 let mut dept_budget_map: HashMap<String, (f64, Vec<f64>)> = HashMap::new();
507 for (dept, proj) in dept_projects {
508 let entry = dept_budget_map
509 .entry(dept.name.clone())
510 .or_insert((dept.budget, Vec::new()));
511 if let Some(p) = proj {
512 entry.1.push(p.budget);
513 }
514 }
515
516 for (dept_name, (total_budget, project_budgets)) in dept_budget_map.iter() {
517 let used: f64 = project_budgets.iter().sum();
518 let remaining = total_budget - used;
519 println!(" {}: Budget ${:.0}, Used ${:.0}, Remaining ${:.0} ({:.1}% utilized)",
520 dept_name, total_budget, used, remaining, (used / total_budget * 100.0));
521 }
522
523 println!("\nRust Query Builder:");
524 println!("let dept_projects = JoinQuery::new(&departments, &projects)");
525 println!(" .left_join(Department::id_r(), Project::department_id_r(), ...)");
526 println!("// Then aggregate using HashMap");
527
528 // ============================================================================
529 // Summary
530 // ============================================================================
531 print_separator("Summary");
532 println!("\n✓ All 15 SQL queries successfully replicated with Rust Query Builder!");
533 println!("\nDemonstrated equivalents for:");
534 println!(" • SELECT with WHERE");
535 println!(" • Projection (SELECT specific columns)");
536 println!(" • Aggregations (COUNT, SUM, AVG, MIN, MAX)");
537 println!(" • GROUP BY");
538 println!(" • ORDER BY");
539 println!(" • LIMIT and OFFSET");
540 println!(" • INNER JOIN and LEFT JOIN");
541 println!(" • Complex conditions (AND, OR, BETWEEN)");
542 println!(" • Subqueries");
543 println!(" • Multi-table operations");
544 println!("\n🎯 Type-safe, compile-time checked, and zero runtime overhead!");
545 println!();
546}