1use rust_queries_builder::{Query, JoinQuery};
7use key_paths_derive::Keypaths;
8use std::collections::HashMap;
9
10#[derive(Debug, Clone, Keypaths)]
11struct Employee {
12 id: u32,
13 name: String,
14 department: String,
15 salary: f64,
16 age: u32,
17 city: String,
18}
19
20#[derive(Debug, Clone, Keypaths)]
21struct Department {
22 id: u32,
23 name: String,
24 budget: f64,
25 location: String,
26}
27
28#[derive(Debug, Clone, Keypaths)]
29struct Project {
30 id: u32,
31 name: String,
32 department_id: u32,
33 budget: f64,
34}
35
36fn create_employees() -> Vec<Employee> {
38 vec![
39 Employee { id: 1, name: "Alice Johnson".to_string(), department: "Engineering".to_string(), salary: 95000.0, age: 32, city: "San Francisco".to_string() },
40 Employee { id: 2, name: "Bob Smith".to_string(), department: "Engineering".to_string(), salary: 87000.0, age: 28, city: "San Francisco".to_string() },
41 Employee { id: 3, name: "Carol White".to_string(), department: "Sales".to_string(), salary: 75000.0, age: 35, city: "New York".to_string() },
42 Employee { id: 4, name: "David Brown".to_string(), department: "Sales".to_string(), salary: 82000.0, age: 41, city: "New York".to_string() },
43 Employee { id: 5, name: "Eve Davis".to_string(), department: "Marketing".to_string(), salary: 71000.0, age: 29, city: "Chicago".to_string() },
44 Employee { id: 6, name: "Frank Wilson".to_string(), department: "Engineering".to_string(), salary: 105000.0, age: 38, city: "Seattle".to_string() },
45 Employee { id: 7, name: "Grace Lee".to_string(), department: "Marketing".to_string(), salary: 68000.0, age: 26, city: "Chicago".to_string() },
46 Employee { id: 8, name: "Henry Taylor".to_string(), department: "HR".to_string(), salary: 62000.0, age: 33, city: "Boston".to_string() },
47 Employee { id: 9, name: "Iris Moore".to_string(), department: "Engineering".to_string(), salary: 92000.0, age: 30, city: "San Francisco".to_string() },
48 Employee { id: 10, name: "Jack Anderson".to_string(), department: "Sales".to_string(), salary: 79000.0, age: 45, city: "New York".to_string() },
49 ]
50}
51
52fn create_departments() -> Vec<Department> {
53 vec![
54 Department { id: 1, name: "Engineering".to_string(), budget: 1500000.0, location: "San Francisco".to_string() },
55 Department { id: 2, name: "Sales".to_string(), budget: 800000.0, location: "New York".to_string() },
56 Department { id: 3, name: "Marketing".to_string(), budget: 600000.0, location: "Chicago".to_string() },
57 Department { id: 4, name: "HR".to_string(), budget: 400000.0, location: "Boston".to_string() },
58 ]
59}
60
61fn create_projects() -> Vec<Project> {
62 vec![
63 Project { id: 1, name: "Cloud Migration".to_string(), department_id: 1, budget: 250000.0 },
64 Project { id: 2, name: "Mobile App".to_string(), department_id: 1, budget: 180000.0 },
65 Project { id: 3, name: "Q4 Campaign".to_string(), department_id: 2, budget: 120000.0 },
66 Project { id: 4, name: "Brand Refresh".to_string(), department_id: 3, budget: 95000.0 },
67 Project { id: 5, name: "Employee Portal".to_string(), department_id: 4, budget: 65000.0 },
68 ]
69}
70
71fn print_separator(title: &str) {
72 println!("\n{}", "=".repeat(80));
73 println!(" {}", title);
74 println!("{}", "=".repeat(80));
75}
76
77fn print_query(sql: &str, description: &str) {
78 println!("\n--- {} ---", description);
79 println!("SQL Query:");
80 println!("{}", sql);
81 println!("\nResults:");
82}
83
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 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 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 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 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 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 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 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 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 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 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 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) .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)); 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 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 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 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 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 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 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 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}
547