flusso_query/handles/
geo.rs1use std::marker::PhantomData;
5
6use serde_json::{Map, Value};
7
8use super::{Sort, SortOrder, exists_q};
9use crate::query::{Query, Root};
10
11#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
13pub struct GeoPoint {
14 pub lat: f64,
16 pub lon: f64,
18}
19
20impl GeoPoint {
21 pub fn new(lat: f64, lon: f64) -> Self {
23 Self { lat, lon }
24 }
25
26 fn to_value(self) -> Value {
28 let mut point = Map::new();
29 point.insert("lat".to_string(), Value::from(self.lat));
30 point.insert("lon".to_string(), Value::from(self.lon));
31 Value::Object(point)
32 }
33}
34
35#[derive(Debug, Clone)]
38pub struct Geo<S = Root> {
39 path: String,
40 _scope: PhantomData<fn() -> S>,
41}
42
43impl<S> Geo<S> {
44 pub fn at(path: impl Into<String>) -> Self {
45 Self {
46 path: path.into(),
47 _scope: PhantomData,
48 }
49 }
50
51 pub fn within(&self, distance: impl Into<String>, center: GeoPoint) -> Query<S> {
53 let mut body = Map::new();
54 body.insert("distance".to_string(), Value::String(distance.into()));
55 body.insert(self.path.clone(), center.to_value());
56 wrap_object("geo_distance", body)
57 }
58
59 pub fn in_bounding_box(&self, top_left: GeoPoint, bottom_right: GeoPoint) -> Query<S> {
61 let mut corners = Map::new();
62 corners.insert("top_left".to_string(), top_left.to_value());
63 corners.insert("bottom_right".to_string(), bottom_right.to_value());
64 let mut body = Map::new();
65 body.insert(self.path.clone(), Value::Object(corners));
66 wrap_object("geo_bounding_box", body)
67 }
68
69 pub fn in_polygon(&self, points: impl IntoIterator<Item = GeoPoint>) -> Query<S> {
71 let vertices = points.into_iter().map(GeoPoint::to_value).collect();
72 let mut inner = Map::new();
73 inner.insert("points".to_string(), Value::Array(vertices));
74 let mut body = Map::new();
75 body.insert(self.path.clone(), Value::Object(inner));
76 wrap_object("geo_polygon", body)
77 }
78
79 pub fn exists(&self) -> Query<S> {
81 exists_q(&self.path)
82 }
83
84 pub fn distance_sort(
86 &self,
87 center: GeoPoint,
88 order: SortOrder,
89 unit: impl Into<String>,
90 ) -> Sort {
91 let mut body = Map::new();
92 body.insert(self.path.clone(), center.to_value());
93 body.insert(
94 "order".to_string(),
95 Value::String(order.as_str().to_string()),
96 );
97 body.insert("unit".to_string(), Value::String(unit.into()));
98 let mut outer = Map::new();
99 outer.insert("_geo_distance".to_string(), Value::Object(body));
100 Sort::raw(Value::Object(outer))
101 }
102}
103
104fn wrap_object<S>(name: &str, body: Map<String, Value>) -> Query<S> {
106 let mut outer = Map::new();
107 outer.insert(name.to_string(), Value::Object(body));
108 Query::leaf(Value::Object(outer))
109}