1use rust_queries_builder::Query;
6use key_paths_derive::Keypaths;
7
8#[derive(Debug, Clone, Keypaths)]
9struct Employee {
10 id: u32,
11 name: String,
12 email: String,
13 department: String,
14 salary: f64,
15}
16
17fn create_test_data() -> Vec<Employee> {
18 vec![
19 Employee { id: 1, name: "Alice Johnson".to_string(), email: "alice@example.com".to_string(), department: "Engineering".to_string(), salary: 95000.0 },
20 Employee { id: 2, name: "Bob Smith".to_string(), email: "bob@example.com".to_string(), department: "Engineering".to_string(), salary: 87000.0 },
21 Employee { id: 3, name: "Carol White".to_string(), email: "carol@example.com".to_string(), department: "Sales".to_string(), salary: 75000.0 },
22 Employee { id: 4, name: "David Brown".to_string(), email: "david@example.com".to_string(), department: "Sales".to_string(), salary: 82000.0 },
23 Employee { id: 5, name: "Eve Davis".to_string(), email: "eve@example.com".to_string(), department: "Marketing".to_string(), salary: 71000.0 },
24 Employee { id: 6, name: "Alice Cooper".to_string(), email: "cooper@example.com".to_string(), department: "Engineering".to_string(), salary: 105000.0 },
25 ]
26}
27
28fn print_test(title: &str, passed: bool) {
29 let status = if passed { "✅ PASS" } else { "❌ FAIL" };
30 println!("{} - {}", status, title);
31}
32
33fn main() {
34 let employees = create_test_data();
35
36 println!("\n╔════════════════════════════════════════════════════════════════╗");
37 println!("║ SQL Equivalence Verification Tests ║");
38 println!("╚════════════════════════════════════════════════════════════════╝\n");
39
40 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 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 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 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 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 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 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 && 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 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 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 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 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 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; print_test("Complex WHERE clause works correctly", test12_pass);
207 println!(" Found {} employees", complex.len());
208
209 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") .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 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 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 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 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; print_test("Email pattern matching works correctly", test17_pass);
274 println!(" Found {} employees with @example.com emails", example_emails);
275
276 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}
323