Skip to content

Commit ab9b2e6

Browse files
fix: enhance expression and raster/vector join operators with new source structures
1 parent bd3faa3 commit ab9b2e6

4 files changed

Lines changed: 246 additions & 75 deletions

File tree

api/src/parameters.rs

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::processes::{RasterOperator, VectorOperator};
12
use anyhow::Context;
23
use geoengine_macros::type_tag;
34
use serde::{Deserialize, Serialize, Serializer};
@@ -365,24 +366,48 @@ impl From<TemporalAggregationMethod>
365366

366367
/// Spatial bounds derivation options for the [`MockPointSource`].
367368
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
368-
#[serde(rename_all = "camelCase", tag = "type")]
369-
#[derive(Default)]
369+
#[serde(rename_all = "camelCase", untagged)]
370+
#[schema(discriminator = "type")]
370371
pub enum SpatialBoundsDerive {
371-
Derive,
372-
Bounds(BoundingBox2D),
373-
#[default]
374-
None,
372+
Derive(SpatialBoundsDeriveDerive),
373+
Bounds(SpatialBoundsDeriveBounds),
374+
None(SpatialBoundsDeriveNone),
375375
}
376376

377+
impl Default for SpatialBoundsDerive {
378+
fn default() -> Self {
379+
SpatialBoundsDerive::None(SpatialBoundsDeriveNone::default())
380+
}
381+
}
382+
383+
#[type_tag(value = "derive")]
384+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema, Default)]
385+
pub struct SpatialBoundsDeriveDerive {}
386+
387+
#[type_tag(value = "bounds")]
388+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
389+
pub struct SpatialBoundsDeriveBounds {
390+
#[serde(flatten)]
391+
pub bounding_box: BoundingBox2D,
392+
}
393+
394+
#[type_tag(value = "none")]
395+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema, Default)]
396+
pub struct SpatialBoundsDeriveNone {}
397+
377398
impl TryFrom<SpatialBoundsDerive> for geoengine_operators::mock::SpatialBoundsDerive {
378399
type Error = anyhow::Error;
379400
fn try_from(value: SpatialBoundsDerive) -> Result<Self, Self::Error> {
380401
Ok(match value {
381-
SpatialBoundsDerive::Derive => geoengine_operators::mock::SpatialBoundsDerive::Derive,
382-
SpatialBoundsDerive::Bounds(bbox) => {
383-
geoengine_operators::mock::SpatialBoundsDerive::Bounds(bbox.try_into()?)
402+
SpatialBoundsDerive::Derive(_) => {
403+
geoengine_operators::mock::SpatialBoundsDerive::Derive
384404
}
385-
SpatialBoundsDerive::None => geoengine_operators::mock::SpatialBoundsDerive::None,
405+
SpatialBoundsDerive::Bounds(bounds) => {
406+
geoengine_operators::mock::SpatialBoundsDerive::Bounds(
407+
bounds.bounding_box.try_into()?,
408+
)
409+
}
410+
SpatialBoundsDerive::None(_) => geoengine_operators::mock::SpatialBoundsDerive::None,
386411
})
387412
}
388413
}
@@ -407,6 +432,48 @@ impl TryFrom<BoundingBox2D> for geoengine_datatypes::primitives::BoundingBox2D {
407432
}
408433
}
409434

435+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
436+
#[schema(no_recursion)]
437+
#[serde(rename_all = "camelCase")]
438+
pub struct SingleRasterSource {
439+
pub raster: RasterOperator,
440+
}
441+
442+
impl TryFrom<SingleRasterSource> for geoengine_operators::engine::SingleRasterSource {
443+
type Error = anyhow::Error;
444+
445+
fn try_from(value: SingleRasterSource) -> Result<Self, Self::Error> {
446+
Ok(Self {
447+
raster: value.raster.try_into()?,
448+
})
449+
}
450+
}
451+
452+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
453+
#[schema(no_recursion)]
454+
#[serde(rename_all = "camelCase")]
455+
pub struct SingleVectorMultipleRasterSources {
456+
pub vector: VectorOperator,
457+
pub rasters: Vec<RasterOperator>,
458+
}
459+
460+
impl TryFrom<SingleVectorMultipleRasterSources>
461+
for geoengine_operators::engine::SingleVectorMultipleRasterSources
462+
{
463+
type Error = anyhow::Error;
464+
465+
fn try_from(value: SingleVectorMultipleRasterSources) -> Result<Self, Self::Error> {
466+
Ok(Self {
467+
vector: value.vector.try_into()?,
468+
rasters: value
469+
.rasters
470+
.into_iter()
471+
.map(std::convert::TryInto::try_into)
472+
.collect::<Result<_, _>>()?,
473+
})
474+
}
475+
}
476+
410477
#[cfg(test)]
411478
mod tests {
412479
#![allow(clippy::float_cmp)] // ok for tests

api/src/processes/processing.rs

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
use crate::parameters::{ColumnNames, FeatureAggregationMethod, TemporalAggregationMethod};
1+
use crate::parameters::{
2+
ColumnNames, FeatureAggregationMethod, SingleRasterSource, SingleVectorMultipleRasterSources,
3+
TemporalAggregationMethod,
4+
};
25
use crate::parameters::{RasterBandDescriptor, RasterDataType};
36
use geoengine_macros::type_tag;
4-
use geoengine_operators::processing::ExpressionParams as OperatorsExpressionParamsStruct;
7+
use geoengine_operators::processing::{
8+
Expression as OperatorsExpression, ExpressionParams as OperatorsExpressionParameters,
9+
RasterVectorJoin as OperatorsRasterVectorJoin,
10+
RasterVectorJoinParams as OperatorsRasterVectorJoinParameters,
11+
};
512
use serde::{Deserialize, Serialize};
613
use utoipa::ToSchema;
714

@@ -87,6 +94,7 @@ use utoipa::ToSchema;
8794
#[serde(rename_all = "camelCase")]
8895
pub struct Expression {
8996
pub params: ExpressionParameters,
97+
pub sources: SingleRasterSource,
9098
}
9199

92100
/// ## Types
@@ -107,15 +115,18 @@ pub struct ExpressionParameters {
107115
pub map_no_data: bool,
108116
}
109117

110-
impl TryFrom<Expression> for OperatorsExpressionParamsStruct {
118+
impl TryFrom<Expression> for OperatorsExpression {
111119
type Error = anyhow::Error;
112120

113121
fn try_from(value: Expression) -> Result<Self, Self::Error> {
114-
Ok(OperatorsExpressionParamsStruct {
115-
expression: value.params.expression,
116-
output_type: value.params.output_type.into(),
117-
output_band: value.params.output_band.map(Into::into),
118-
map_no_data: value.params.map_no_data,
122+
Ok(OperatorsExpression {
123+
params: OperatorsExpressionParameters {
124+
expression: value.params.expression,
125+
output_type: value.params.output_type.into(),
126+
output_band: value.params.output_band.map(Into::into),
127+
map_no_data: value.params.map_no_data,
128+
},
129+
sources: value.sources.try_into()?,
119130
})
120131
}
121132
}
@@ -187,6 +198,7 @@ impl TryFrom<Expression> for OperatorsExpressionParamsStruct {
187198
#[serde(rename_all = "camelCase")]
188199
pub struct RasterVectorJoin {
189200
pub params: RasterVectorJoinParameters,
201+
pub sources: Box<SingleVectorMultipleRasterSources>,
190202
}
191203

192204
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
@@ -215,25 +227,38 @@ pub struct RasterVectorJoinParameters {
215227
pub temporal_aggregation_ignore_no_data: bool,
216228
}
217229

218-
use geoengine_operators::processing::RasterVectorJoinParams as OperatorsRasterVectorJoinParams;
219-
220-
impl TryFrom<RasterVectorJoin> for OperatorsRasterVectorJoinParams {
230+
impl TryFrom<RasterVectorJoin> for OperatorsRasterVectorJoin {
221231
type Error = anyhow::Error;
222232

223233
fn try_from(value: RasterVectorJoin) -> Result<Self, Self::Error> {
224-
Ok(OperatorsRasterVectorJoinParams {
225-
names: value.params.names.into(),
226-
feature_aggregation: value.params.feature_aggregation.into(),
227-
feature_aggregation_ignore_no_data: value.params.feature_aggregation_ignore_no_data,
228-
temporal_aggregation: value.params.temporal_aggregation.into(),
229-
temporal_aggregation_ignore_no_data: value.params.temporal_aggregation_ignore_no_data,
234+
Ok(OperatorsRasterVectorJoin {
235+
params: OperatorsRasterVectorJoinParameters {
236+
names: value.params.names.into(),
237+
feature_aggregation: value.params.feature_aggregation.into(),
238+
feature_aggregation_ignore_no_data: value.params.feature_aggregation_ignore_no_data,
239+
temporal_aggregation: value.params.temporal_aggregation.into(),
240+
temporal_aggregation_ignore_no_data: value
241+
.params
242+
.temporal_aggregation_ignore_no_data,
243+
},
244+
sources: (*value.sources).try_into()?,
230245
})
231246
}
232247
}
233248

234249
#[cfg(test)]
235250
mod tests {
251+
236252
use super::*;
253+
use crate::{
254+
parameters::{Coordinate2D, SpatialBoundsDerive},
255+
processes::{
256+
RasterOperator, VectorOperator,
257+
source::{
258+
GdalSource, GdalSourceParameters, MockPointSource, MockPointSourceParameters,
259+
},
260+
},
261+
};
237262

238263
#[test]
239264
fn it_converts_expressions() {
@@ -245,17 +270,26 @@ mod tests {
245270
output_band: None,
246271
map_no_data: true,
247272
},
273+
sources: SingleRasterSource {
274+
raster: RasterOperator::GdalSource(GdalSource {
275+
r#type: Default::default(),
276+
params: GdalSourceParameters {
277+
data: "example_data".to_string(),
278+
overview_level: None,
279+
},
280+
}),
281+
},
248282
};
249283

250-
let ops = OperatorsExpressionParamsStruct::try_from(api).expect("conversion failed");
284+
let ops = OperatorsExpression::try_from(api).expect("conversion failed");
251285

252-
assert_eq!(ops.expression, "2 * A + B");
286+
assert_eq!(ops.params.expression, "2 * A + B");
253287
assert_eq!(
254-
ops.output_type,
288+
ops.params.output_type,
255289
geoengine_datatypes::raster::RasterDataType::F32
256290
);
257-
assert!(ops.output_band.is_none());
258-
assert!(ops.map_no_data);
291+
assert!(ops.params.output_band.is_none());
292+
assert!(ops.params.map_no_data);
259293
}
260294

261295
#[test]
@@ -269,23 +303,39 @@ mod tests {
269303
temporal_aggregation: TemporalAggregationMethod::Mean,
270304
temporal_aggregation_ignore_no_data: false,
271305
},
306+
sources: Box::new(SingleVectorMultipleRasterSources {
307+
vector: VectorOperator::MockPointSource(MockPointSource {
308+
r#type: Default::default(),
309+
params: MockPointSourceParameters {
310+
points: vec![Coordinate2D { x: 0.0, y: 0.0 }],
311+
spatial_bounds: SpatialBoundsDerive::Derive(Default::default()),
312+
},
313+
}),
314+
rasters: vec![RasterOperator::GdalSource(GdalSource {
315+
r#type: Default::default(),
316+
params: GdalSourceParameters {
317+
data: "example_data".to_string(),
318+
overview_level: None,
319+
},
320+
})],
321+
}),
272322
};
273323

274-
let ops_params = OperatorsRasterVectorJoinParams::try_from(api).expect("conversion failed");
324+
let ops_params = OperatorsRasterVectorJoin::try_from(api).expect("conversion failed");
275325

276326
assert!(matches!(
277-
ops_params.names,
327+
ops_params.params.names,
278328
geoengine_operators::processing::ColumnNames::Names(_)
279329
));
280330
assert_eq!(
281-
ops_params.feature_aggregation,
331+
ops_params.params.feature_aggregation,
282332
geoengine_operators::processing::FeatureAggregationMethod::First
283333
);
284-
assert!(ops_params.feature_aggregation_ignore_no_data);
334+
assert!(ops_params.params.feature_aggregation_ignore_no_data);
285335
assert_eq!(
286-
ops_params.temporal_aggregation,
336+
ops_params.params.temporal_aggregation,
287337
geoengine_operators::processing::TemporalAggregationMethod::Mean
288338
);
289-
assert!(!ops_params.temporal_aggregation_ignore_no_data);
339+
assert!(!ops_params.params.temporal_aggregation_ignore_no_data);
290340
}
291341
}

api/src/processes/source.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ mod tests {
161161
Coordinate2D { x: 1.0, y: 2.0 },
162162
Coordinate2D { x: 3.0, y: 4.0 },
163163
],
164-
spatial_bounds: SpatialBoundsDerive::Derive,
164+
spatial_bounds: SpatialBoundsDerive::Derive(Default::default()),
165165
},
166166
};
167167

@@ -181,7 +181,7 @@ mod tests {
181181
r#type: Default::default(),
182182
params: MockPointSourceParameters {
183183
points: vec![Coordinate2D { x: 1.0, y: 2.0 }],
184-
spatial_bounds: SpatialBoundsDerive::Derive,
184+
spatial_bounds: SpatialBoundsDerive::Derive(Default::default()),
185185
},
186186
}));
187187

0 commit comments

Comments
 (0)