pub struct Query<'a, 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: 'static + Clone> Query<'a, T>
impl<'a, T: 'static + Clone> Query<'a, T>
Sourcepub fn new(data: &'a [T]) -> Self
pub fn new(data: &'a [T]) -> Self
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?
examples/doc_examples.rs (line 42)
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
examples/advanced_query_builder.rs (line 118)
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}examples/sql_verification.rs (line 44)
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}examples/sql_comparison.rs (line 103)
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 where_<F>(
self,
path: KeyPaths<T, F>,
predicate: impl Fn(&F) -> bool + 'static,
) -> Selfwhere
F: 'static,
pub fn where_<F>(
self,
path: KeyPaths<T, F>,
predicate: impl Fn(&F) -> bool + 'static,
) -> Selfwhere
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?
examples/doc_examples.rs (line 43)
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
examples/advanced_query_builder.rs (line 151)
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}examples/sql_verification.rs (line 90)
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}examples/sql_comparison.rs (line 104)
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 all(&self) -> Vec<&T>
pub fn all(&self) -> Vec<&T>
Examples found in repository?
examples/doc_examples.rs (line 45)
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
examples/advanced_query_builder.rs (line 243)
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}examples/sql_verification.rs (line 91)
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}examples/sql_comparison.rs (line 105)
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 first(&self) -> Option<&T>
pub fn first(&self) -> Option<&T>
Examples found in repository?
examples/advanced_query_builder.rs (line 194)
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?
examples/doc_examples.rs (line 101)
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
examples/advanced_query_builder.rs (line 153)
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}examples/sql_verification.rs (line 165)
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}examples/sql_comparison.rs (line 149)
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 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?
examples/doc_examples.rs (line 131)
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
examples/advanced_query_builder.rs (line 177)
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?
examples/doc_examples.rs (line 132)
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
examples/advanced_query_builder.rs (line 185)
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 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.
§Arguments
path- The key-path to the field to order by
§Example
ⓘ
let sorted = query.order_by(Product::name_r());Examples found in repository?
examples/advanced_query_builder.rs (line 253)
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
examples/sql_verification.rs (line 74)
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}examples/sql_comparison.rs (line 307)
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.
§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?
examples/doc_examples.rs (line 86)
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
examples/advanced_query_builder.rs (line 126)
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}examples/sql_verification.rs (line 59)
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.
§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?
examples/advanced_query_builder.rs (line 133)
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
examples/sql_verification.rs (line 44)
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}examples/sql_comparison.rs (line 236)
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 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?
examples/doc_examples.rs (line 73)
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
examples/advanced_query_builder.rs (line 118)
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}examples/sql_comparison.rs (line 127)
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 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.
§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?
examples/doc_examples.rs (line 117)
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
examples/advanced_query_builder.rs (line 140)
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}examples/sql_verification.rs (line 255)
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}examples/sql_comparison.rs (line 207)
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?
examples/doc_examples.rs (line 102)
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
examples/advanced_query_builder.rs (line 154)
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}examples/sql_comparison.rs (line 175)
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?
examples/doc_examples.rs (line 103)
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
examples/advanced_query_builder.rs (line 155)
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}examples/sql_verification.rs (line 177)
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}examples/sql_comparison.rs (line 176)
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?
examples/advanced_query_builder.rs (line 156)
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
examples/sql_verification.rs (line 189)
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}examples/sql_comparison.rs (line 177)
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?
examples/advanced_query_builder.rs (line 157)
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
examples/sql_verification.rs (line 190)
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}examples/sql_comparison.rs (line 178)
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?
examples/advanced_query_builder.rs (line 206)
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}Auto Trait Implementations§
impl<'a, T> Freeze for Query<'a, T>
impl<'a, T> !RefUnwindSafe for Query<'a, T>
impl<'a, T> !Send for Query<'a, T>
impl<'a, T> !Sync for Query<'a, T>
impl<'a, T> Unpin for Query<'a, T>
impl<'a, T> !UnwindSafe for Query<'a, T>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more