Skip to main content

routee_compass/plugin/input/
input_json_extensions.rs

1use crate::{app::compass::CompassAppError, plugin::PluginError};
2
3use super::{InputField, InputPluginError};
4use geo;
5use routee_compass_core::model::network::{EdgeId, VertexId};
6use serde_json::{self, json};
7
8pub trait InputJsonExtensions {
9    fn get_origin_coordinate(&self) -> Result<geo::Coord<f32>, InputPluginError>;
10    fn get_destination_coordinate(&self) -> Result<Option<geo::Coord<f32>>, InputPluginError>;
11    fn add_origin_vertex(&mut self, vertex_id: VertexId) -> Result<(), InputPluginError>;
12    fn add_destination_vertex(&mut self, vertex_id: VertexId) -> Result<(), InputPluginError>;
13    fn add_origin_edge(&mut self, edge_id: EdgeId) -> Result<(), InputPluginError>;
14    fn add_destination_edge(&mut self, edge_id: EdgeId) -> Result<(), InputPluginError>;
15    fn get_origin_vertex(&self) -> Result<VertexId, InputPluginError>;
16    fn get_destination_vertex(&self) -> Result<Option<VertexId>, InputPluginError>;
17    fn get_origin_edge(&self) -> Result<EdgeId, InputPluginError>;
18    fn get_destination_edge(&self) -> Result<Option<EdgeId>, InputPluginError>;
19    fn get_grid_search(&self) -> Option<&serde_json::Value>;
20    fn add_query_weight_estimate(&mut self, weight: f64) -> Result<(), InputPluginError>;
21    fn get_query_weight_estimate(&self) -> Result<Option<f64>, CompassAppError>;
22}
23
24impl InputJsonExtensions for serde_json::Value {
25    fn get_origin_coordinate(&self) -> Result<geo::Coord<f32>, InputPluginError> {
26        let origin_x = self
27            .get(InputField::OriginX.to_str())
28            .ok_or(InputPluginError::MissingExpectedQueryField(
29                InputField::OriginX,
30            ))?
31            .as_f64()
32            .ok_or_else(|| {
33                InputPluginError::QueryFieldHasInvalidType(InputField::OriginX, String::from("f64"))
34            })?;
35        let origin_y = self
36            .get(InputField::OriginY.to_str())
37            .ok_or(InputPluginError::MissingExpectedQueryField(
38                InputField::OriginY,
39            ))?
40            .as_f64()
41            .ok_or_else(|| {
42                InputPluginError::QueryFieldHasInvalidType(InputField::OriginY, String::from("f64"))
43            })?;
44        Ok(geo::Coord::from((origin_x as f32, origin_y as f32)))
45    }
46    fn get_destination_coordinate(&self) -> Result<Option<geo::Coord<f32>>, InputPluginError> {
47        let x_field = InputField::DestinationX;
48        let y_field = InputField::DestinationY;
49        let x_opt = self.get(x_field.to_str());
50        let y_opt = self.get(y_field.to_str());
51        match (x_opt, y_opt) {
52            (None, None) => Ok(None),
53            (None, Some(_)) => Err(InputPluginError::MissingQueryFieldPair(y_field, x_field)),
54            (Some(_), None) => Err(InputPluginError::MissingQueryFieldPair(x_field, y_field)),
55            (Some(x_json), Some(y_json)) => {
56                let x = x_json.as_f64().ok_or_else(|| {
57                    InputPluginError::QueryFieldHasInvalidType(x_field, String::from("f64"))
58                })?;
59                let y = y_json.as_f64().ok_or_else(|| {
60                    InputPluginError::QueryFieldHasInvalidType(y_field, String::from("f64"))
61                })?;
62                Ok(Some(geo::Coord::from((x as f32, y as f32))))
63            }
64        }
65    }
66    fn add_origin_vertex(&mut self, vertex_id: VertexId) -> Result<(), InputPluginError> {
67        match self {
68            serde_json::Value::Object(map) => {
69                map.insert(
70                    InputField::OriginVertex.to_string(),
71                    serde_json::Value::from(vertex_id.0),
72                );
73                Ok(())
74            }
75            _ => Err(InputPluginError::UnexpectedQueryStructure(String::from(
76                "InputQuery is not a JSON object",
77            ))),
78        }
79    }
80    fn add_destination_vertex(&mut self, vertex_id: VertexId) -> Result<(), InputPluginError> {
81        match self {
82            serde_json::Value::Object(map) => {
83                map.insert(
84                    InputField::DestinationVertex.to_string(),
85                    serde_json::Value::from(vertex_id.0),
86                );
87                Ok(())
88            }
89            _ => Err(InputPluginError::UnexpectedQueryStructure(String::from(
90                "InputQuery is not a JSON object",
91            ))),
92        }
93    }
94
95    fn get_origin_vertex(&self) -> Result<VertexId, InputPluginError> {
96        self.get(InputField::OriginVertex.to_str())
97            .ok_or(InputPluginError::MissingExpectedQueryField(
98                InputField::OriginVertex,
99            ))?
100            .as_u64()
101            .map(|v| VertexId(v as usize))
102            .ok_or_else(|| {
103                InputPluginError::QueryFieldHasInvalidType(
104                    InputField::OriginVertex,
105                    String::from("u64"),
106                )
107            })
108    }
109
110    fn get_destination_vertex(&self) -> Result<Option<VertexId>, InputPluginError> {
111        match self.get(InputField::DestinationVertex.to_str()) {
112            None => Ok(None),
113            Some(v) => v
114                .as_u64()
115                .map(|v| Some(VertexId(v as usize)))
116                .ok_or_else(|| {
117                    InputPluginError::QueryFieldHasInvalidType(
118                        InputField::DestinationVertex,
119                        String::from("u64"),
120                    )
121                }),
122        }
123    }
124
125    fn get_origin_edge(&self) -> Result<EdgeId, InputPluginError> {
126        self.get(InputField::OriginEdge.to_str())
127            .ok_or(InputPluginError::MissingExpectedQueryField(
128                InputField::OriginEdge,
129            ))?
130            .as_u64()
131            .map(|v| EdgeId(v as usize))
132            .ok_or_else(|| {
133                InputPluginError::QueryFieldHasInvalidType(
134                    InputField::OriginEdge,
135                    String::from("u64"),
136                )
137            })
138    }
139
140    fn get_destination_edge(&self) -> Result<Option<EdgeId>, InputPluginError> {
141        match self.get(InputField::DestinationEdge.to_str()) {
142            None => Ok(None),
143            Some(v) => v.as_u64().map(|v| Some(EdgeId(v as usize))).ok_or_else(|| {
144                InputPluginError::QueryFieldHasInvalidType(
145                    InputField::OriginEdge,
146                    String::from("u64"),
147                )
148            }),
149        }
150    }
151    fn get_grid_search(&self) -> Option<&serde_json::Value> {
152        self.get(InputField::GridSearch.to_str())
153    }
154
155    fn add_origin_edge(&mut self, edge_id: EdgeId) -> Result<(), InputPluginError> {
156        match self {
157            serde_json::Value::Object(map) => {
158                map.insert(
159                    InputField::OriginEdge.to_string(),
160                    serde_json::Value::from(edge_id.0),
161                );
162                Ok(())
163            }
164            _ => Err(InputPluginError::UnexpectedQueryStructure(String::from(
165                "InputQuery is not a JSON object",
166            ))),
167        }
168    }
169
170    fn add_destination_edge(&mut self, edge_id: EdgeId) -> Result<(), InputPluginError> {
171        match self {
172            serde_json::Value::Object(map) => {
173                map.insert(
174                    InputField::DestinationEdge.to_string(),
175                    serde_json::Value::from(edge_id.0),
176                );
177                Ok(())
178            }
179            _ => Err(InputPluginError::UnexpectedQueryStructure(String::from(
180                "InputQuery is not a JSON object",
181            ))),
182        }
183    }
184
185    fn add_query_weight_estimate(&mut self, weight: f64) -> Result<(), InputPluginError> {
186        match self {
187            serde_json::Value::Object(map) => {
188                map.insert(InputField::QueryWeightEstimate.to_string(), json!(weight));
189                Ok(())
190            }
191            _ => Err(InputPluginError::UnexpectedQueryStructure(String::from(
192                "InputQuery is not a JSON object",
193            ))),
194        }
195    }
196
197    fn get_query_weight_estimate(&self) -> Result<Option<f64>, CompassAppError> {
198        match self.get(InputField::QueryWeightEstimate.to_str()) {
199            None => Ok(None),
200            Some(v) => v.as_f64().map(Some).ok_or_else(|| {
201                let ipe = InputPluginError::QueryFieldHasInvalidType(
202                    InputField::QueryWeightEstimate,
203                    String::from("f64"),
204                );
205                let pe = PluginError::InputPluginFailed { source: ipe };
206                CompassAppError::PluginError(pe)
207            }),
208        }
209    }
210}
211
212// pub type DecodeOp<T> = Box<dyn Fn(&serde_json::Value) -> Option<T>>;
213
214// fn get_from_json<T>(
215//     value: &serde_json::Value,
216//     field: InputField,
217//     op: DecodeOp<T>,
218// ) -> Result<T, InputPluginError> {
219//     let at_field = value.get(field.to_string());
220//     match at_field {
221//         None => Err(InputPluginError::MissingField(field.to_string())),
222//         Some(v) => op(v).ok_or_else( ||InputPluginError::QueryFieldHasInvalidType(field.to_string(), ())),
223//     };
224// }
225
226// fn get_f64(v: &serde_json::Value) -> Result<f64, InputPluginError> {
227
228//     get_from_json(v, field, |v| v.as_f64())
229//     v.as_f64().ok_or_else( ||InputPluginError::QueryFieldHasInvalidType((), ())
230// }