spatial_queries/
spatial_queries.rs

1use spatio::{Point, Spatio};
2
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("=== Spatio - Spatial Queries ===\n");
5
6    let mut db = Spatio::memory()?;
7    println!("✓ Created in-memory database\n");
8
9    // === SETUP: Insert World Cities ===
10    println!("Setting up test data...");
11
12    let cities = vec![
13        ("New York", Point::new(-74.0060, 40.7128)),
14        ("London", Point::new(-0.1278, 51.5074)),
15        ("Paris", Point::new(2.3522, 48.8566)),
16        ("Berlin", Point::new(13.4050, 52.5200)),
17        ("Madrid", Point::new(-3.7038, 40.4168)),
18        ("Rome", Point::new(12.4964, 41.9028)),
19        ("Tokyo", Point::new(139.6503, 35.6762)),
20        ("Sydney", Point::new(151.2093, -33.8688)),
21        ("Mumbai", Point::new(72.8777, 19.0760)),
22        ("Cairo", Point::new(31.2357, 30.0444)),
23        ("São Paulo", Point::new(-46.6333, -23.5505)),
24        ("Mexico City", Point::new(-99.1332, 19.4326)),
25    ];
26
27    for (name, point) in &cities {
28        db.insert_point("world_cities", point, name.as_bytes(), None)?;
29    }
30    println!("   Added {} cities to spatial index\n", cities.len());
31
32    // === 1. RADIUS QUERIES ===
33    println!("1. Radius-Based Queries (query_within_radius)");
34    println!("----------------------------------------------");
35
36    let london = Point::new(-0.1278, 51.5074);
37
38    // Find cities within 500km of London
39    let nearby_500km = db.query_within_radius("world_cities", &london, 500_000.0, 10)?;
40    println!("   Cities within 500km of London: {}", nearby_500km.len());
41    for (_, data, _) in &nearby_500km {
42        println!("     - {}", String::from_utf8_lossy(data));
43    }
44
45    // Find cities within 2000km of London
46    let nearby_2000km = db.query_within_radius("world_cities", &london, 2_000_000.0, 10)?;
47    println!(
48        "\n   Cities within 2000km of London: {}",
49        nearby_2000km.len()
50    );
51    for (_, data, _) in &nearby_2000km {
52        println!("     - {}", String::from_utf8_lossy(data));
53    }
54
55    // Use limit to get only closest N cities
56    let closest_3 = db.query_within_radius("world_cities", &london, f64::INFINITY, 3)?;
57    println!("\n   Closest 3 cities to London:");
58    for (i, (_, data, _)) in closest_3.iter().enumerate() {
59        println!("     {}. {}", i + 1, String::from_utf8_lossy(data));
60    }
61    println!();
62
63    // === 2. EXISTENCE CHECKS ===
64    println!("2. Existence Checks (contains_point)");
65    println!("-------------------------------------");
66
67    let has_nearby_500km = db.intersects_radius("world_cities", &london, 500_000.0)?;
68    let has_nearby_100km = db.intersects_radius("world_cities", &london, 100_000.0)?;
69
70    println!("   Any cities within 500km of London? {}", has_nearby_500km);
71    println!("   Any cities within 100km of London? {}", has_nearby_100km);
72
73    // === 3. COUNTING POINTS ===
74    println!("3. Counting Points (count_within_radius)");
75    println!("----------------------------------------");
76
77    let count_500km = db.count_within_radius("world_cities", &london, 500_000.0)?;
78    let count_1000km = db.count_within_radius("world_cities", &london, 1_000_000.0)?;
79    let count_2000km = db.count_within_radius("world_cities", &london, 2_000_000.0)?;
80
81    println!("   Cities within 500km of London: {}", count_500km);
82    println!("   Cities within 1000km of London: {}", count_1000km);
83    println!("   Cities within 2000km of London: {}", count_2000km);
84    println!();
85
86    // === 4. BOUNDING BOX QUERIES ===
87    println!("4. Bounding Box Queries");
88    println!("-----------------------");
89
90    // European bounding box (min_lon, min_lat, max_lon, max_lat)
91    println!("   European region (lon: -10 to 20, lat: 40 to 60):");
92    let europe_cities = db.find_within_bounds("world_cities", -10.0, 40.0, 20.0, 60.0, 20)?;
93    println!("     Found {} cities:", europe_cities.len());
94    for (point, data) in &europe_cities {
95        println!(
96            "       - {} at ({:.2}°, {:.2}°)",
97            String::from_utf8_lossy(data),
98            point.x(),
99            point.y()
100        );
101    }
102
103    // Asia-Pacific region
104    println!("\n   Asia-Pacific region (lon: 70 to 180, lat: -40 to 40):");
105    let asia_cities = db.find_within_bounds("world_cities", 70.0, -40.0, 180.0, 40.0, 20)?;
106    println!("     Found {} cities:", asia_cities.len());
107    for (_, data) in &asia_cities {
108        println!("       - {}", String::from_utf8_lossy(data));
109    }
110
111    // Americas region
112    println!("\n   Americas region (lon: -130 to -30, lat: -60 to 60):");
113    let americas_cities = db.find_within_bounds("world_cities", -130.0, -60.0, -30.0, 60.0, 20)?;
114    println!("     Found {} cities:", americas_cities.len());
115    for (_, data) in &americas_cities {
116        println!("       - {}", String::from_utf8_lossy(data));
117    }
118    println!();
119
120    // === 5. BOUNDING BOX INTERSECTION ===
121    println!("5. Bounding Box Intersection (intersects_bounds)");
122    println!("------------------------------------------------");
123
124    let has_european = db.intersects_bounds("world_cities", -10.0, 40.0, 20.0, 60.0)?;
125    let has_antarctica = db.intersects_bounds("world_cities", -180.0, -90.0, 180.0, -60.0)?;
126
127    println!("   European region has cities? {}", has_european);
128    println!("   Antarctica region has cities? {}", has_antarctica);
129    println!();
130
131    // === 6. MULTIPLE NAMESPACES ===
132    println!("6. Multiple Namespaces");
133    println!("----------------------");
134
135    // Add some landmarks in London
136    let london_landmarks = vec![
137        ("Big Ben", Point::new(-0.1245, 51.4994)),
138        ("Tower Bridge", Point::new(-0.0754, 51.5055)),
139        ("London Eye", Point::new(-0.1195, 51.5033)),
140        ("Buckingham Palace", Point::new(-0.1419, 51.5014)),
141    ];
142
143    for (name, point) in &london_landmarks {
144        db.insert_point("landmarks", point, name.as_bytes(), None)?;
145    }
146
147    println!("   Added {} London landmarks", london_landmarks.len());
148
149    // Query different namespaces from same location
150    let center_london = Point::new(-0.1278, 51.5074);
151
152    let nearby_cities = db.query_within_radius("world_cities", &center_london, 10_000.0, 10)?;
153    let nearby_landmarks = db.query_within_radius("landmarks", &center_london, 10_000.0, 10)?;
154
155    println!("   Within 10km of center London:");
156    println!("     Cities: {}", nearby_cities.len());
157    println!("     Landmarks: {}", nearby_landmarks.len());
158
159    println!("\n   Landmarks within 2km:");
160    let close_landmarks = db.query_within_radius("landmarks", &center_london, 2_000.0, 10)?;
161    for (_, data, _) in &close_landmarks {
162        println!("     - {}", String::from_utf8_lossy(data));
163    }
164    println!();
165
166    // === 7. QUERY LIMITS ===
167    println!("7. Query Result Limiting");
168    println!("------------------------");
169
170    let all_cities = db.query_within_radius("world_cities", &london, f64::INFINITY, 100)?;
171    let top_5 = db.query_within_radius("world_cities", &london, f64::INFINITY, 5)?;
172    let top_3 = db.query_within_radius("world_cities", &london, f64::INFINITY, 3)?;
173
174    println!("   Total cities in database: {}", all_cities.len());
175    println!("   With limit=5: {} cities", top_5.len());
176    println!("   With limit=3: {} cities", top_3.len());
177    println!();
178
179    // === SUMMARY ===
180    let stats = db.stats();
181    println!("=== Query Summary ===");
182    println!("Database statistics:");
183    println!("  Total keys: {}", stats.key_count);
184    println!("  Operations: {}", stats.operations_count);
185
186    println!("\nSpatial query methods demonstrated:");
187    println!("  • query_within_radius - Find points within distance");
188    println!("  • contains_point - Check if points exist in radius");
189    println!("  • count_within_radius - Count points efficiently");
190    println!("  • find_within_bounds - Rectangular region queries");
191    println!("  • intersects_bounds - Check bounding box intersection");
192    println!("  • Multiple namespaces - Organize different point types");
193    println!("  • Result limiting - Control query result size");
194
195    Ok(())
196}