routee_compass/plugin/input/
input_json_extensions.rs1use 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