Query

Struct Query 

Source
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 queried
  • T - 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>

Source

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
Hide additional 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}
Source

pub fn where_<F>( self, path: KeyPaths<T, F>, predicate: impl Fn(&F) -> bool + 'static, ) -> Self
where F: 'static,

Adds a filter predicate using a key-path.

§Arguments
  • path - The key-path to the field to filter on
  • predicate - 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
Hide additional 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}
Source

pub fn all(&self) -> Vec<&T>

Returns all items matching the query filters.

§Example
let results = query.all();
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
Hide additional 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}
Source

pub fn first(&self) -> Option<&T>

Returns the first item matching the query filters.

§Example
let first = query.first();
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}
Source

pub fn count(&self) -> usize

Returns the count of items matching the query filters.

§Example
let count = query.count();
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
Hide additional 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}
Source

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
Hide additional 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}
Source

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
Hide additional 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}
Source

pub fn order_by<F>(&self, path: KeyPaths<T, F>) -> Vec<T>
where F: Ord + Clone + 'static,

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
Hide additional 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}
Source

pub fn order_by_desc<F>(&self, path: KeyPaths<T, F>) -> Vec<T>
where F: Ord + Clone + 'static,

Orders results by a field in descending order.

§Arguments
  • path - The key-path to the field to order by
§Example
let sorted = query.order_by_desc(Product::stock_r());
Source

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
Hide additional 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}
Source

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
Hide additional 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}
Source

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
Hide additional 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}
Source

pub fn group_by<F>(&self, path: KeyPaths<T, F>) -> HashMap<F, Vec<T>>
where F: Eq + Hash + Clone + 'static,

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
Hide additional 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}
Source

pub fn sum<F>(&self, path: KeyPaths<T, F>) -> F
where F: Clone + Add<Output = F> + Default + 'static,

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
Hide additional 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}
Source

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
Hide additional 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}
Source

pub fn min<F>(&self, path: KeyPaths<T, F>) -> Option<F>
where F: Ord + Clone + 'static,

Finds the minimum value of a field.

§Arguments
  • path - The key-path to the field
§Example
let min_stock = query.min(Product::stock_r());
Source

pub fn max<F>(&self, path: KeyPaths<T, F>) -> Option<F>
where F: Ord + Clone + 'static,

Finds the maximum value of a field.

§Arguments
  • path - The key-path to the field
§Example
let max_stock = query.max(Product::stock_r());
Source

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
Hide additional 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}
Source

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
Hide additional 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}
Source

pub fn exists(&self) -> bool

Checks if any items match the query filters.

§Example
let has_results = query.exists();
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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.