advanced_query_builder/
advanced_query_builder.rs

1// Demonstrates advanced query builder with SQL-like operations using keypaths
2// This example shows how to:
3// 1. Select specific fields (projection)
4// 2. Order results by fields (ascending/descending)
5// 3. Group by fields with aggregations
6// 4. Limit and paginate results
7// 5. Compute aggregates (count, sum, avg, min, max)
8// 6. Chain complex queries
9// cargo run --example advanced_query_builder
10
11use rust_queries_builder::Query;
12use key_paths_derive::Keypaths;
13
14#[derive(Debug, Clone, Keypaths)]
15struct Product {
16    id: u32,
17    name: String,
18    price: f64,
19    category: String,
20    stock: u32,
21    rating: f64,
22}
23
24// Helper function to create sample products
25fn create_product_catalog() -> Vec<Product> {
26    vec![
27        Product {
28            id: 1,
29            name: "Laptop Pro".to_string(),
30            price: 1299.99,
31            category: "Electronics".to_string(),
32            stock: 15,
33            rating: 4.8,
34        },
35        Product {
36            id: 2,
37            name: "Wireless Mouse".to_string(),
38            price: 29.99,
39            category: "Electronics".to_string(),
40            stock: 50,
41            rating: 4.5,
42        },
43        Product {
44            id: 3,
45            name: "Mechanical Keyboard".to_string(),
46            price: 129.99,
47            category: "Electronics".to_string(),
48            stock: 30,
49            rating: 4.7,
50        },
51        Product {
52            id: 4,
53            name: "Office Chair".to_string(),
54            price: 299.99,
55            category: "Furniture".to_string(),
56            stock: 20,
57            rating: 4.6,
58        },
59        Product {
60            id: 5,
61            name: "Standing Desk".to_string(),
62            price: 499.99,
63            category: "Furniture".to_string(),
64            stock: 10,
65            rating: 4.9,
66        },
67        Product {
68            id: 6,
69            name: "USB-C Hub".to_string(),
70            price: 49.99,
71            category: "Electronics".to_string(),
72            stock: 100,
73            rating: 4.3,
74        },
75        Product {
76            id: 7,
77            name: "Monitor 27\"".to_string(),
78            price: 349.99,
79            category: "Electronics".to_string(),
80            stock: 25,
81            rating: 4.7,
82        },
83        Product {
84            id: 8,
85            name: "Desk Lamp".to_string(),
86            price: 39.99,
87            category: "Furniture".to_string(),
88            stock: 40,
89            rating: 4.2,
90        },
91        Product {
92            id: 9,
93            name: "Webcam HD".to_string(),
94            price: 79.99,
95            category: "Electronics".to_string(),
96            stock: 35,
97            rating: 4.4,
98        },
99        Product {
100            id: 10,
101            name: "Bookshelf".to_string(),
102            price: 149.99,
103            category: "Furniture".to_string(),
104            stock: 15,
105            rating: 4.5,
106        },
107    ]
108}
109
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}
284