spatio_server/
reader.rs

1use crate::protocol::{CurrentLocation, LocationUpdate, Stats};
2use spatio::Spatio;
3use spatio_types::geo::{DistanceMetric, Point, Polygon};
4use spatio_types::point::Point3d;
5use std::sync::Arc;
6
7#[derive(Clone)]
8pub struct Reader {
9    db: Arc<Spatio>,
10}
11
12impl Reader {
13    pub fn new(db: Arc<Spatio>) -> Self {
14        Self { db }
15    }
16
17    pub fn get(&self, namespace: &str, id: &str) -> Result<Option<CurrentLocation>, String> {
18        match self.db.get(namespace, id) {
19            Ok(Some(loc)) => Ok(Some(CurrentLocation {
20                object_id: loc.object_id,
21                position: loc.position,
22                metadata: serde_json::to_vec(&loc.metadata).unwrap_or_default(),
23            })),
24            Ok(None) => Ok(None),
25            Err(e) => Err(e.to_string()),
26        }
27        .map_err(|e| format!("Internal error: {}", e))
28    }
29
30    pub fn query_radius(
31        &self,
32        namespace: &str,
33        center: &Point3d,
34        radius: f64,
35        limit: usize,
36    ) -> Result<Vec<(CurrentLocation, f64)>, String> {
37        self.db
38            .query_radius(namespace, center, radius, limit)
39            .map(|results| {
40                results
41                    .into_iter()
42                    .map(|(loc, dist)| {
43                        (
44                            CurrentLocation {
45                                object_id: loc.object_id,
46                                position: loc.position,
47                                metadata: serde_json::to_vec(&loc.metadata).unwrap_or_default(),
48                            },
49                            dist,
50                        )
51                    })
52                    .collect()
53            })
54            .map_err(|e| format!("Internal error: {}", e))
55    }
56
57    pub fn knn(
58        &self,
59        namespace: &str,
60        center: &Point3d,
61        k: usize,
62    ) -> Result<Vec<(CurrentLocation, f64)>, String> {
63        self.db
64            .knn(namespace, center, k)
65            .map(|results| {
66                results
67                    .into_iter()
68                    .map(|(loc, dist)| {
69                        (
70                            CurrentLocation {
71                                object_id: loc.object_id,
72                                position: loc.position,
73                                metadata: serde_json::to_vec(&loc.metadata).unwrap_or_default(),
74                            },
75                            dist,
76                        )
77                    })
78                    .collect()
79            })
80            .map_err(|e| format!("Internal error: {}", e))
81    }
82
83    pub fn stats(&self) -> Stats {
84        let s = self.db.stats();
85        Stats {
86            object_count: s.hot_state_objects,
87            memory_usage_bytes: s.memory_usage_bytes,
88        }
89    }
90
91    pub fn query_bbox(
92        &self,
93        namespace: &str,
94        min_x: f64,
95        min_y: f64,
96        max_x: f64,
97        max_y: f64,
98        limit: usize,
99    ) -> Result<Vec<CurrentLocation>, String> {
100        self.db
101            .query_bbox(namespace, min_x, min_y, max_x, max_y, limit)
102            .map(|results| {
103                results
104                    .into_iter()
105                    .map(|loc| CurrentLocation {
106                        object_id: loc.object_id,
107                        position: loc.position,
108                        metadata: serde_json::to_vec(&loc.metadata).unwrap_or_default(),
109                    })
110                    .collect()
111            })
112            .map_err(|e| format!("Internal error: {}", e))
113    }
114
115    pub fn query_cylinder(
116        &self,
117        namespace: &str,
118        center: Point,
119        min_z: f64,
120        max_z: f64,
121        radius: f64,
122        limit: usize,
123    ) -> Result<Vec<(CurrentLocation, f64)>, String> {
124        self.db
125            .query_within_cylinder(namespace, center, min_z, max_z, radius, limit)
126            .map(|results| {
127                results
128                    .into_iter()
129                    .map(|(loc, dist)| {
130                        (
131                            CurrentLocation {
132                                object_id: loc.object_id,
133                                position: loc.position,
134                                metadata: serde_json::to_vec(&loc.metadata).unwrap_or_default(),
135                            },
136                            dist,
137                        )
138                    })
139                    .collect()
140            })
141            .map_err(|e| format!("Internal error: {}", e))
142    }
143
144    pub fn query_trajectory(
145        &self,
146        namespace: &str,
147        id: &str,
148        start_time: Option<f64>,
149        end_time: Option<f64>,
150        limit: usize,
151    ) -> Result<Vec<LocationUpdate>, String> {
152        let start = start_time
153            .map(|t| std::time::UNIX_EPOCH + std::time::Duration::from_secs_f64(t))
154            .unwrap_or(std::time::UNIX_EPOCH);
155        let end = end_time
156            .map(|t| std::time::UNIX_EPOCH + std::time::Duration::from_secs_f64(t))
157            .unwrap_or_else(std::time::SystemTime::now);
158
159        self.db
160            .query_trajectory(namespace, id, start, end, limit)
161            .map(|results| {
162                results
163                    .into_iter()
164                    .map(|upd| {
165                        let timestamp = upd
166                            .timestamp
167                            .duration_since(std::time::UNIX_EPOCH)
168                            .unwrap_or_default()
169                            .as_secs_f64();
170
171                        LocationUpdate {
172                            timestamp,
173                            position: upd.position,
174                            metadata: serde_json::to_vec(&upd.metadata).unwrap_or_default(),
175                        }
176                    })
177                    .collect()
178            })
179            .map_err(|e| e.to_string())
180    }
181
182    #[allow(clippy::too_many_arguments)]
183    pub fn query_bbox_3d(
184        &self,
185        namespace: &str,
186        min_x: f64,
187        min_y: f64,
188        min_z: f64,
189        max_x: f64,
190        max_y: f64,
191        max_z: f64,
192        limit: usize,
193    ) -> Result<Vec<CurrentLocation>, String> {
194        self.db
195            .query_within_bbox_3d(namespace, min_x, min_y, min_z, max_x, max_y, max_z, limit)
196            .map(|results| {
197                results
198                    .into_iter()
199                    .map(|loc| CurrentLocation {
200                        object_id: loc.object_id,
201                        position: loc.position,
202                        metadata: serde_json::to_vec(&loc.metadata).unwrap_or_default(),
203                    })
204                    .collect()
205            })
206            .map_err(|e| format!("Internal error: {}", e))
207    }
208
209    pub fn query_near(
210        &self,
211        namespace: &str,
212        id: &str,
213        radius: f64,
214        limit: usize,
215    ) -> Result<Vec<(CurrentLocation, f64)>, String> {
216        self.db
217            .query_near(namespace, id, radius, limit)
218            .map(|results| {
219                results
220                    .into_iter()
221                    .map(|(loc, dist)| {
222                        (
223                            CurrentLocation {
224                                object_id: loc.object_id,
225                                position: loc.position,
226                                metadata: serde_json::to_vec(&loc.metadata).unwrap_or_default(),
227                            },
228                            dist,
229                        )
230                    })
231                    .collect()
232            })
233            .map_err(|e| format!("Internal error: {}", e))
234    }
235
236    pub fn contains(
237        &self,
238        namespace: &str,
239        polygon: &Polygon,
240        limit: usize,
241    ) -> Result<Vec<CurrentLocation>, String> {
242        self.db
243            .query_polygon(namespace, polygon, limit)
244            .map(|results| {
245                results
246                    .into_iter()
247                    .map(|loc| CurrentLocation {
248                        object_id: loc.object_id,
249                        position: loc.position,
250                        metadata: serde_json::to_vec(&loc.metadata).unwrap_or_default(),
251                    })
252                    .collect()
253            })
254            .map_err(|e| format!("Internal error: {}", e))
255    }
256
257    pub fn distance(
258        &self,
259        namespace: &str,
260        id1: &str,
261        id2: &str,
262        metric: Option<DistanceMetric>,
263    ) -> Result<Option<f64>, String> {
264        self.db
265            .distance_between(namespace, id1, id2, metric.unwrap_or_default())
266            .map_err(|e| format!("Internal error: {}", e))
267    }
268
269    pub fn distance_to(
270        &self,
271        namespace: &str,
272        id: &str,
273        point: &Point,
274        metric: Option<DistanceMetric>,
275    ) -> Result<Option<f64>, String> {
276        self.db
277            .distance_to(namespace, id, point, metric.unwrap_or_default())
278            .map_err(|e| format!("Internal error: {}", e))
279    }
280
281    pub fn convex_hull(&self, namespace: &str) -> Result<Option<Polygon>, String> {
282        self.db
283            .convex_hull(namespace)
284            .map_err(|e| format!("Internal error: {}", e))
285    }
286
287    pub fn bounding_box(
288        &self,
289        namespace: &str,
290    ) -> Result<Option<spatio_types::bbox::BoundingBox2D>, String> {
291        self.db
292            .bounding_box(namespace)
293            .map(|opt| opt.map(spatio_types::bbox::BoundingBox2D::from_rect))
294            .map_err(|e| format!("Internal error: {}", e))
295    }
296}