• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geo-engine / geoengine / 23550417448

25 Mar 2026 03:52PM UTC coverage: 87.389%. First build
23550417448

Pull #1114

github

web-flow
Merge 17fe5e1a3 into dccacebf2
Pull Request #1114: feat: STAC dataset import

598 of 1795 new or added lines in 12 files covered. (33.31%)

113704 of 130113 relevant lines covered (87.39%)

497604.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.89
/services/src/api/model/processing_graphs/source.rs
1
use crate::api::model::{
2
    datatypes::Coordinate2D, processing_graphs::parameters::SpatialBoundsDerive,
3
};
4
use geoengine_datatypes::dataset::NamedData;
5
use geoengine_macros::{api_operator, type_tag};
6
use geoengine_operators::{
7
    mock::{
8
        MockPointSource as OperatorsMockPointSource,
9
        MockPointSourceParams as OperatorsMockPointSourceParameters,
10
    },
11
    source::{
12
        GdalSource as OperatorsGdalSource, GdalSourceParameters as OperatorsGdalSourceParameters,
13
        MultiBandGdalSource as OperatorsMultiBandGdalSource,
14
        MultiBandGdalSourceParameters as OperatorsMultiBandGdalSourceParameters,
15
    },
16
};
17
use serde::{Deserialize, Serialize};
18
use utoipa::ToSchema;
19

20
/// The [`GdalSource`] is a source operator that reads raster data using GDAL.
21
/// The counterpart for vector data is the [`OgrSource`].
22
///
23
/// ## Errors
24
///
25
/// If the given dataset does not exist or is not readable, an error is thrown.
26
///
27
#[api_operator(
90✔
28
    title = "GDAL Source",
90✔
29
    examples(json!({
90✔
30
        "type": "GdalSource",
31
        "params": {
32
            "data": "ndvi",
33
            "overviewLevel": null
34
        }
35
    }))
36
)]
37
pub struct GdalSource {
38
    pub params: GdalSourceParameters,
39
}
40

41
/// Parameters for the [`GdalSource`] operator.
42
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
43
#[serde(rename_all = "camelCase")]
44
pub struct GdalSourceParameters {
45
    /// Dataset name or identifier to be loaded.
46
    #[schema(examples("ndvi"))]
47
    pub data: String,
48

49
    /// *Optional*: overview level to use.
50
    ///
51
    /// If not provided, the data source will determine the resolution, i.e., uses its native resolution.
52
    #[schema(examples(3))]
53
    pub overview_level: Option<u32>,
54
}
55

56
impl TryFrom<GdalSource> for OperatorsGdalSource {
57
    type Error = anyhow::Error;
58
    fn try_from(value: GdalSource) -> Result<Self, Self::Error> {
42✔
59
        Ok(OperatorsGdalSource {
60
            params: OperatorsGdalSourceParameters {
61
                data: serde_json::from_str::<NamedData>(&serde_json::to_string(
42✔
62
                    &value.params.data,
42✔
63
                )?)?,
×
64
                overview_level: value.params.overview_level,
42✔
65
            },
66
        })
67
    }
42✔
68
}
69

70
/// The [`MultiBandGdalSource`] is a source operator that reads multi-band raster data using GDAL.
71
#[api_operator(
90✔
72
    title = "Multi Band GDAL Source",
90✔
73
    examples(json!({
90✔
74
        "type": "MultiBandGdalSource",
75
        "params": {
76
            "data": "sentinel-2-l2a_EPSG32632_U16_10",
77
            "overviewLevel": null
78
        }
79
    }))
80
)]
81
pub struct MultiBandGdalSource {
82
    pub params: GdalSourceParameters,
83
}
84

85
impl TryFrom<MultiBandGdalSource> for OperatorsMultiBandGdalSource {
86
    type Error = anyhow::Error;
87

88
    fn try_from(value: MultiBandGdalSource) -> Result<Self, Self::Error> {
5✔
89
        Ok(OperatorsMultiBandGdalSource {
90
            params: OperatorsMultiBandGdalSourceParameters {
91
                data: serde_json::from_str::<NamedData>(&serde_json::to_string(
5✔
92
                    &value.params.data,
5✔
NEW
93
                )?)?,
×
94
                overview_level: value.params.overview_level,
5✔
95
            },
96
        })
97
    }
5✔
98
}
99

100
/// The [`MockPointSource`] is a source operator that provides mock vector point data for testing and development purposes.
101
///
102
#[api_operator(
90✔
103
    title = "Mock Point Source",
90✔
104
    examples(json!({
90✔
105
        "type": "MockPointSource",
106
        "params": {
107
            "points": [ { "x": 1.0, "y": 2.0 }, { "x": 3.0, "y": 4.0 } ],
108
            "spatialBounds": { "type": "derive" }
109
        }
110
    }))
111
)]
112
pub struct MockPointSource {
113
    pub params: MockPointSourceParameters,
114
}
115

116
/// Parameters for the [`MockPointSource`] operator.
117
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
118
#[serde(rename_all = "camelCase")]
119
pub struct MockPointSourceParameters {
120
    /// Points to be output by the mock point source.
121
    ///
122
    #[schema(examples(json!([
123
        { "x": 1.0, "y": 2.0 },
124
        { "x": 3.0, "y": 4.0 }
125
    ])))]
126
    pub points: Vec<Coordinate2D>,
127

128
    /// Defines how the spatial bounds of the source are derived.
129
    ///
130
    /// Defaults to `None`.
131
    #[schema(examples(json!({ "type": "derive" })))]
132
    pub spatial_bounds: SpatialBoundsDerive,
133
}
134

135
impl TryFrom<MockPointSource> for OperatorsMockPointSource {
136
    type Error = anyhow::Error;
137
    fn try_from(value: MockPointSource) -> Result<Self, Self::Error> {
9✔
138
        Ok(OperatorsMockPointSource {
139
            params: OperatorsMockPointSourceParameters {
140
                points: value.params.points.into_iter().map(Into::into).collect(),
9✔
141
                spatial_bounds: value.params.spatial_bounds.try_into()?,
9✔
142
            },
143
        })
144
    }
9✔
145
}
146

147
#[cfg(test)]
148
mod tests {
149
    use super::*;
150
    use crate::api::model::processing_graphs::{RasterOperator, TypedOperator, VectorOperator};
151
    use geoengine_operators::engine::TypedOperator as OperatorsTypedOperator;
152

153
    #[test]
154
    fn it_converts_into_gdal_source() {
1✔
155
        let api_operator = GdalSource {
1✔
156
            r#type: Default::default(),
1✔
157
            params: GdalSourceParameters {
1✔
158
                data: "example_dataset".to_string(),
1✔
159
                overview_level: None,
1✔
160
            },
1✔
161
        };
1✔
162

163
        let operators_operator: OperatorsGdalSource =
1✔
164
            api_operator.try_into().expect("it should convert");
1✔
165

166
        assert_eq!(
1✔
167
            operators_operator.params.data,
168
            NamedData::with_system_name("example_dataset")
1✔
169
        );
170

171
        let typed_operator = TypedOperator::Raster(RasterOperator::GdalSource(GdalSource {
1✔
172
            r#type: Default::default(),
1✔
173
            params: GdalSourceParameters {
1✔
174
                data: "example_dataset".to_string(),
1✔
175
                overview_level: None,
1✔
176
            },
1✔
177
        }));
1✔
178

179
        OperatorsTypedOperator::try_from(typed_operator).expect("it should convert");
1✔
180
    }
1✔
181

182
    #[test]
183
    fn it_converts_into_multi_band_gdal_source() {
1✔
184
        let api_operator = MultiBandGdalSource {
1✔
185
            r#type: Default::default(),
1✔
186
            params: GdalSourceParameters {
1✔
187
                data: "example_dataset".to_string(),
1✔
188
                overview_level: None,
1✔
189
            },
1✔
190
        };
1✔
191

192
        let operators_operator: OperatorsMultiBandGdalSource =
1✔
193
            api_operator.try_into().expect("it should convert");
1✔
194

195
        assert_eq!(
1✔
196
            operators_operator.params.data,
197
            NamedData::with_system_name("example_dataset")
1✔
198
        );
199

200
        let typed_operator =
1✔
201
            TypedOperator::Raster(RasterOperator::MultiBandGdalSource(MultiBandGdalSource {
1✔
202
                r#type: Default::default(),
1✔
203
                params: GdalSourceParameters {
1✔
204
                    data: "example_dataset".to_string(),
1✔
205
                    overview_level: None,
1✔
206
                },
1✔
207
            }));
1✔
208

209
        OperatorsTypedOperator::try_from(typed_operator).expect("it should convert");
1✔
210
    }
1✔
211

212
    #[test]
213
    fn it_converts_mock_point_source() {
1✔
214
        let api_operator = MockPointSource {
1✔
215
            r#type: Default::default(),
1✔
216
            params: MockPointSourceParameters {
1✔
217
                points: vec![
1✔
218
                    Coordinate2D { x: 1.0, y: 2.0 },
1✔
219
                    Coordinate2D { x: 3.0, y: 4.0 },
1✔
220
                ],
1✔
221
                spatial_bounds: SpatialBoundsDerive::Derive(Default::default()),
1✔
222
            },
1✔
223
        };
1✔
224

225
        let operators_operator: OperatorsMockPointSource =
1✔
226
            api_operator.try_into().expect("it should convert");
1✔
227

228
        assert_eq!(
1✔
229
            operators_operator.params.points,
230
            vec![
1✔
231
                geoengine_datatypes::primitives::Coordinate2D { x: 1.0, y: 2.0 },
1✔
232
                geoengine_datatypes::primitives::Coordinate2D { x: 3.0, y: 4.0 }
1✔
233
            ]
234
        );
235

236
        let typed_operator =
1✔
237
            TypedOperator::Vector(VectorOperator::MockPointSource(MockPointSource {
1✔
238
                r#type: Default::default(),
1✔
239
                params: MockPointSourceParameters {
1✔
240
                    points: vec![Coordinate2D { x: 1.0, y: 2.0 }],
1✔
241
                    spatial_bounds: SpatialBoundsDerive::Derive(Default::default()),
1✔
242
                },
1✔
243
            }));
1✔
244

245
        OperatorsTypedOperator::try_from(typed_operator).expect("it should convert");
1✔
246
    }
1✔
247
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc