(
name: &str,
func: &ast::Function,
table: &crate::resolver::columns::ResolvedTable,
extra_filter: Option<&ast::Expr>,
)
| 265 | } |
| 266 | |
| 267 | fn plan_spatial_from_where( |
| 268 | name: &str, |
| 269 | func: &ast::Function, |
| 270 | table: &crate::resolver::columns::ResolvedTable, |
| 271 | extra_filter: Option<&ast::Expr>, |
| 272 | ) -> Result<Option<SqlPlan>> { |
| 273 | let predicate = match name { |
| 274 | "st_dwithin" => SpatialPredicate::DWithin, |
| 275 | "st_contains" => SpatialPredicate::Contains, |
| 276 | "st_intersects" => SpatialPredicate::Intersects, |
| 277 | "st_within" => SpatialPredicate::Within, |
| 278 | _ => return Ok(None), |
| 279 | }; |
| 280 | let args = extract_func_args(func)?; |
| 281 | if args.is_empty() { |
| 282 | return Err(SqlError::MissingField { |
| 283 | field: "geometry column".into(), |
| 284 | context: name.into(), |
| 285 | }); |
| 286 | } |
| 287 | let field = extract_column_name(&args[0])?; |
| 288 | let geom_arg = args.get(1).ok_or_else(|| SqlError::MissingField { |
| 289 | field: "query geometry".into(), |
| 290 | context: name.into(), |
| 291 | })?; |
| 292 | let geom_str = extract_geometry_arg(geom_arg)?; |
| 293 | let geometry: nodedb_types::geometry::Geometry = |
| 294 | sonic_rs::from_str(&geom_str).map_err(|e| SqlError::InvalidFunction { |
| 295 | detail: format!("invalid geometry in {name}: {e}"), |
| 296 | })?; |
| 297 | let issues = nodedb_spatial::validate::validate_geometry(&geometry); |
| 298 | if !issues.is_empty() { |
| 299 | return Err(SqlError::InvalidFunction { |
| 300 | detail: format!("invalid geometry in {name}: {}", issues.join("; ")), |
| 301 | }); |
| 302 | } |
| 303 | let distance = if args.len() >= 3 { |
| 304 | extract_float(&args[2]).unwrap_or(0.0) |
| 305 | } else { |
| 306 | 0.0 |
| 307 | }; |
| 308 | Ok(Some(SqlPlan::SpatialScan { |
| 309 | collection: table.name.clone(), |
| 310 | field, |
| 311 | predicate, |
| 312 | query_geometry: geometry, |
| 313 | distance_meters: distance, |
| 314 | attribute_filters: extra_filter_to_filters(extra_filter)?, |
| 315 | limit: 1000, |
| 316 | projection: Vec::new(), |
| 317 | })) |
| 318 | } |
no test coverage detected