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

geo-engine / geoengine / 4126366810

pending completion
4126366810

push

github

GitHub
Merge #733

287 of 287 new or added lines in 11 files covered. (100.0%)

90438 of 102730 relevant lines covered (88.03%)

76338.47 hits per line

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

44.12
/services/src/api/model/operators.rs
1
use crate::api::model::datatypes::{
2
    Coordinate2D, DateTimeParseFormat, MultiLineString, MultiPoint, MultiPolygon, NoGeometry,
3
    QueryRectangle, RasterPropertiesEntryType, RasterPropertiesKey, SpatialResolution, StringPair,
4
    TimeInstance, TimeStep, VectorQueryRectangle,
5
};
6
use async_trait::async_trait;
7
use geoengine_operators::engine::{MetaData, ResultDescriptor};
8
use serde::{Deserialize, Serialize};
9
use std::collections::HashMap;
10
use std::fmt::Debug;
11
use std::marker::PhantomData;
12
use std::path::PathBuf;
13
use utoipa::ToSchema;
14

15
use super::datatypes::{
16
    BoundingBox2D, FeatureDataType, Measurement, RasterDataType, SpatialPartition2D,
17
    SpatialReferenceOption, TimeInterval, VectorDataType,
18
};
19

20
/// A `ResultDescriptor` for raster queries
21
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
52✔
22
#[serde(rename_all = "camelCase")]
23
pub struct RasterResultDescriptor {
24
    pub data_type: RasterDataType,
25
    pub spatial_reference: SpatialReferenceOption,
26
    pub measurement: Measurement,
27
    pub time: Option<TimeInterval>,
28
    pub bbox: Option<SpatialPartition2D>,
29
    pub resolution: Option<SpatialResolution>,
30
}
31

32
impl From<geoengine_operators::engine::RasterResultDescriptor> for RasterResultDescriptor {
33
    fn from(value: geoengine_operators::engine::RasterResultDescriptor) -> Self {
56✔
34
        Self {
56✔
35
            data_type: value.data_type.into(),
56✔
36
            spatial_reference: value.spatial_reference.into(),
56✔
37
            measurement: value.measurement.into(),
56✔
38
            time: value.time.map(Into::into),
56✔
39
            bbox: value.bbox.map(Into::into),
56✔
40
            resolution: value.resolution.map(Into::into),
56✔
41
        }
56✔
42
    }
56✔
43
}
44

45
impl From<RasterResultDescriptor> for geoengine_operators::engine::RasterResultDescriptor {
46
    fn from(value: RasterResultDescriptor) -> Self {
5✔
47
        Self {
5✔
48
            data_type: value.data_type.into(),
5✔
49
            spatial_reference: value.spatial_reference.into(),
5✔
50
            measurement: value.measurement.into(),
5✔
51
            time: value.time.map(Into::into),
5✔
52
            bbox: value.bbox.map(Into::into),
5✔
53
            resolution: value.resolution.map(Into::into),
5✔
54
        }
5✔
55
    }
5✔
56
}
57

58
/// An enum to differentiate between `Operator` variants
59
#[derive(Clone, Debug, Serialize, Deserialize)]
×
60
#[serde(tag = "type", content = "operator")]
61
pub enum TypedOperator {
62
    Vector(Box<dyn geoengine_operators::engine::VectorOperator>),
63
    Raster(Box<dyn geoengine_operators::engine::RasterOperator>),
64
    Plot(Box<dyn geoengine_operators::engine::PlotOperator>),
65
}
66

67
impl<'a> ToSchema<'a> for TypedOperator {
68
    fn schema() -> (&'a str, utoipa::openapi::RefOr<utoipa::openapi::Schema>) {
×
69
        use utoipa::openapi::*;
×
70
        (
×
71
            "TypedOperator",
×
72
            ObjectBuilder::new()
×
73
            .property(
×
74
                "type",
×
75
                ObjectBuilder::new()
×
76
                    .schema_type(SchemaType::String)
×
77
                    .enum_values(Some(vec!["Vector", "Raster", "Plot"]))
×
78
            )
×
79
            .required("type")
×
80
            .property(
×
81
                "operator",
×
82
                ObjectBuilder::new()
×
83
                    .property(
×
84
                        "type",
×
85
                        Object::with_type(SchemaType::String)
×
86
                    )
×
87
                    .required("type")
×
88
                    .property(
×
89
                        "params",
×
90
                        Object::with_type(SchemaType::Object)
×
91
                    )
×
92
                    .property(
×
93
                        "sources",
×
94
                        Object::with_type(SchemaType::Object)
×
95
                    )
×
96
            )
×
97
            .required("operator")
×
98
            .example(Some(serde_json::json!(
×
99
                {"type": "MockPointSource", "params": {"points": [{"x": 0.0, "y": 0.1}, {"x": 1.0, "y": 1.1}]}
×
100
            })))
×
101
            .description(Some("An enum to differentiate between `Operator` variants"))
×
102
            .into()
×
103
        )
×
104
    }
×
105
}
106

107
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
116✔
108
#[serde(rename_all = "camelCase")]
109
pub struct VectorResultDescriptor {
110
    pub data_type: VectorDataType,
111
    pub spatial_reference: SpatialReferenceOption,
112
    pub columns: HashMap<String, VectorColumnInfo>,
113
    pub time: Option<TimeInterval>,
114
    pub bbox: Option<BoundingBox2D>,
115
}
116

117
impl From<geoengine_operators::engine::VectorResultDescriptor> for VectorResultDescriptor {
118
    fn from(value: geoengine_operators::engine::VectorResultDescriptor) -> Self {
19✔
119
        Self {
19✔
120
            data_type: value.data_type.into(),
19✔
121
            spatial_reference: value.spatial_reference.into(),
19✔
122
            columns: value
19✔
123
                .columns
19✔
124
                .into_iter()
19✔
125
                .map(|(key, value)| (key, value.into()))
23✔
126
                .collect(),
19✔
127
            time: value.time.map(Into::into),
19✔
128
            bbox: value.bbox.map(Into::into),
19✔
129
        }
19✔
130
    }
19✔
131
}
132

133
impl From<VectorResultDescriptor> for geoengine_operators::engine::VectorResultDescriptor {
134
    fn from(value: VectorResultDescriptor) -> Self {
4✔
135
        Self {
4✔
136
            data_type: value.data_type.into(),
4✔
137
            spatial_reference: value.spatial_reference.into(),
4✔
138
            columns: value
4✔
139
                .columns
4✔
140
                .into_iter()
4✔
141
                .map(|(key, value)| (key, value.into()))
20✔
142
                .collect(),
4✔
143
            time: value.time.map(Into::into),
4✔
144
            bbox: value.bbox.map(Into::into),
4✔
145
        }
4✔
146
    }
4✔
147
}
148

149
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, ToSchema)]
115✔
150
#[serde(rename_all = "camelCase")]
151
pub struct VectorColumnInfo {
152
    pub data_type: FeatureDataType,
153
    pub measurement: Measurement,
154
}
155

156
impl From<geoengine_operators::engine::VectorColumnInfo> for VectorColumnInfo {
157
    fn from(value: geoengine_operators::engine::VectorColumnInfo) -> Self {
23✔
158
        Self {
23✔
159
            data_type: value.data_type.into(),
23✔
160
            measurement: value.measurement.into(),
23✔
161
        }
23✔
162
    }
23✔
163
}
164

165
impl From<VectorColumnInfo> for geoengine_operators::engine::VectorColumnInfo {
166
    fn from(value: VectorColumnInfo) -> Self {
20✔
167
        Self {
20✔
168
            data_type: value.data_type.into(),
20✔
169
            measurement: value.measurement.into(),
20✔
170
        }
20✔
171
    }
20✔
172
}
173

174
/// A `ResultDescriptor` for plot queries
175
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
×
176
#[serde(rename_all = "camelCase")]
177
pub struct PlotResultDescriptor {
178
    pub spatial_reference: SpatialReferenceOption,
179
    pub time: Option<TimeInterval>,
180
    pub bbox: Option<BoundingBox2D>,
181
}
182

183
impl From<geoengine_operators::engine::PlotResultDescriptor> for PlotResultDescriptor {
184
    fn from(value: geoengine_operators::engine::PlotResultDescriptor) -> Self {
×
185
        Self {
×
186
            spatial_reference: value.spatial_reference.into(),
×
187
            time: value.time.map(Into::into),
×
188
            bbox: value.bbox.map(Into::into),
×
189
        }
×
190
    }
×
191
}
192

193
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, ToSchema)]
16✔
194
#[serde(rename_all = "camelCase", tag = "type")]
195
pub enum TypedResultDescriptor {
196
    Plot(PlotResultDescriptor),
197
    Raster(RasterResultDescriptor),
198
    Vector(VectorResultDescriptor),
199
}
200

201
impl From<geoengine_operators::engine::TypedResultDescriptor> for TypedResultDescriptor {
202
    fn from(value: geoengine_operators::engine::TypedResultDescriptor) -> Self {
68✔
203
        match value {
68✔
204
            geoengine_operators::engine::TypedResultDescriptor::Plot(p) => Self::Plot(p.into()),
×
205
            geoengine_operators::engine::TypedResultDescriptor::Raster(r) => Self::Raster(r.into()),
52✔
206
            geoengine_operators::engine::TypedResultDescriptor::Vector(v) => Self::Vector(v.into()),
16✔
207
        }
208
    }
68✔
209
}
210

211
impl From<geoengine_operators::engine::PlotResultDescriptor> for TypedResultDescriptor {
212
    fn from(value: geoengine_operators::engine::PlotResultDescriptor) -> Self {
×
213
        Self::Plot(value.into())
×
214
    }
×
215
}
216

217
impl From<PlotResultDescriptor> for TypedResultDescriptor {
218
    fn from(value: PlotResultDescriptor) -> Self {
×
219
        Self::Plot(value)
×
220
    }
×
221
}
222

223
impl From<geoengine_operators::engine::RasterResultDescriptor> for TypedResultDescriptor {
224
    fn from(value: geoengine_operators::engine::RasterResultDescriptor) -> Self {
×
225
        Self::Raster(value.into())
×
226
    }
×
227
}
228

229
impl From<RasterResultDescriptor> for TypedResultDescriptor {
230
    fn from(value: RasterResultDescriptor) -> Self {
×
231
        Self::Raster(value)
×
232
    }
×
233
}
234

235
impl From<geoengine_operators::engine::VectorResultDescriptor> for TypedResultDescriptor {
236
    fn from(value: geoengine_operators::engine::VectorResultDescriptor) -> Self {
2✔
237
        Self::Vector(value.into())
2✔
238
    }
2✔
239
}
240

241
impl From<VectorResultDescriptor> for TypedResultDescriptor {
242
    fn from(value: VectorResultDescriptor) -> Self {
×
243
        Self::Vector(value)
×
244
    }
×
245
}
246

247
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize, ToSchema)]
×
248
pub struct MockDatasetDataSourceLoadingInfo {
249
    pub points: Vec<Coordinate2D>,
250
}
251

252
impl From<geoengine_operators::mock::MockDatasetDataSourceLoadingInfo>
253
    for MockDatasetDataSourceLoadingInfo
254
{
255
    fn from(value: geoengine_operators::mock::MockDatasetDataSourceLoadingInfo) -> Self {
×
256
        Self {
×
257
            points: value.points.into_iter().map(Into::into).collect(),
×
258
        }
×
259
    }
×
260
}
261

262
impl From<MockDatasetDataSourceLoadingInfo>
263
    for geoengine_operators::mock::MockDatasetDataSourceLoadingInfo
264
{
265
    fn from(value: MockDatasetDataSourceLoadingInfo) -> Self {
×
266
        Self {
×
267
            points: value.points.into_iter().map(Into::into).collect(),
×
268
        }
×
269
    }
×
270
}
271

272
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
20✔
273
#[serde(rename_all = "camelCase")]
274
pub struct StaticMetaData<L, R, Q> {
275
    pub loading_info: L,
276
    pub result_descriptor: R,
277
    #[serde(skip)]
278
    pub phantom: PhantomData<Q>,
279
}
280

281
impl
282
    From<
283
        geoengine_operators::engine::StaticMetaData<
284
            geoengine_operators::mock::MockDatasetDataSourceLoadingInfo,
285
            geoengine_operators::engine::VectorResultDescriptor,
286
            geoengine_datatypes::primitives::QueryRectangle<
287
                geoengine_datatypes::primitives::BoundingBox2D,
288
            >,
289
        >,
290
    >
291
    for StaticMetaData<
292
        MockDatasetDataSourceLoadingInfo,
293
        VectorResultDescriptor,
294
        QueryRectangle<BoundingBox2D>,
295
    >
296
{
297
    fn from(
×
298
        value: geoengine_operators::engine::StaticMetaData<
×
299
            geoengine_operators::mock::MockDatasetDataSourceLoadingInfo,
×
300
            geoengine_operators::engine::VectorResultDescriptor,
×
301
            geoengine_datatypes::primitives::QueryRectangle<
×
302
                geoengine_datatypes::primitives::BoundingBox2D,
×
303
            >,
×
304
        >,
×
305
    ) -> Self {
×
306
        Self {
×
307
            loading_info: value.loading_info.into(),
×
308
            result_descriptor: value.result_descriptor.into(),
×
309
            phantom: Default::default(),
×
310
        }
×
311
    }
×
312
}
313

314
impl
315
    From<
316
        geoengine_operators::engine::StaticMetaData<
317
            geoengine_operators::source::OgrSourceDataset,
318
            geoengine_operators::engine::VectorResultDescriptor,
319
            geoengine_datatypes::primitives::QueryRectangle<
320
                geoengine_datatypes::primitives::BoundingBox2D,
321
            >,
322
        >,
323
    > for StaticMetaData<OgrSourceDataset, VectorResultDescriptor, QueryRectangle<BoundingBox2D>>
324
{
325
    fn from(
1✔
326
        value: geoengine_operators::engine::StaticMetaData<
1✔
327
            geoengine_operators::source::OgrSourceDataset,
1✔
328
            geoengine_operators::engine::VectorResultDescriptor,
1✔
329
            geoengine_datatypes::primitives::QueryRectangle<
1✔
330
                geoengine_datatypes::primitives::BoundingBox2D,
1✔
331
            >,
1✔
332
        >,
1✔
333
    ) -> Self {
1✔
334
        Self {
1✔
335
            loading_info: value.loading_info.into(),
1✔
336
            result_descriptor: value.result_descriptor.into(),
1✔
337
            phantom: Default::default(),
1✔
338
        }
1✔
339
    }
1✔
340
}
341

342
#[async_trait]
343
impl<L, R, Q> MetaData<L, R, Q> for StaticMetaData<L, R, Q>
344
where
345
    L: Debug + Clone + Send + Sync + 'static,
346
    R: Debug + Send + Sync + 'static + ResultDescriptor,
347
    Q: Debug + Clone + Send + Sync + 'static,
348
{
349
    async fn loading_info(&self, _query: Q) -> geoengine_operators::util::Result<L> {
×
350
        Ok(self.loading_info.clone())
×
351
    }
×
352

353
    async fn result_descriptor(&self) -> geoengine_operators::util::Result<R> {
×
354
        Ok(self.result_descriptor.clone())
×
355
    }
×
356

357
    fn box_clone(&self) -> Box<dyn MetaData<L, R, Q>> {
×
358
        Box::new(self.clone())
×
359
    }
×
360
}
361

362
pub type MockMetaData =
363
    StaticMetaData<MockDatasetDataSourceLoadingInfo, VectorResultDescriptor, VectorQueryRectangle>;
364
pub type OgrMetaData =
365
    StaticMetaData<OgrSourceDataset, VectorResultDescriptor, VectorQueryRectangle>;
366

367
impl From<MockMetaData>
368
    for geoengine_operators::engine::StaticMetaData<
369
        geoengine_operators::mock::MockDatasetDataSourceLoadingInfo,
370
        geoengine_operators::engine::VectorResultDescriptor,
371
        geoengine_datatypes::primitives::QueryRectangle<
372
            geoengine_datatypes::primitives::BoundingBox2D,
373
        >,
374
    >
375
{
376
    fn from(value: MockMetaData) -> Self {
×
377
        Self {
×
378
            loading_info: value.loading_info.into(),
×
379
            result_descriptor: value.result_descriptor.into(),
×
380
            phantom: Default::default(),
×
381
        }
×
382
    }
×
383
}
384

385
impl From<OgrMetaData>
386
    for geoengine_operators::engine::StaticMetaData<
387
        geoengine_operators::source::OgrSourceDataset,
388
        geoengine_operators::engine::VectorResultDescriptor,
389
        geoengine_datatypes::primitives::QueryRectangle<
390
            geoengine_datatypes::primitives::BoundingBox2D,
391
        >,
392
    >
393
{
394
    fn from(value: OgrMetaData) -> Self {
4✔
395
        Self {
4✔
396
            loading_info: value.loading_info.into(),
4✔
397
            result_descriptor: value.result_descriptor.into(),
4✔
398
            phantom: Default::default(),
4✔
399
        }
4✔
400
    }
4✔
401
}
402

403
impl<'a> ToSchema<'a> for MockMetaData {
404
    fn schema() -> (&'a str, utoipa::openapi::RefOr<utoipa::openapi::Schema>) {
×
405
        use utoipa::openapi::*;
×
406
        (
×
407
            "MockMetaData",
×
408
            ObjectBuilder::new()
×
409
                .property(
×
410
                    "loadingInfo",
×
411
                    Ref::from_schema_name("MockDatasetDataSourceLoadingInfo"),
×
412
                )
×
413
                .required("loadingInfo")
×
414
                .property(
×
415
                    "resultDescriptor",
×
416
                    Ref::from_schema_name("VectorResultDescriptor"),
×
417
                )
×
418
                .required("resultDescriptor")
×
419
                .into(),
×
420
        )
×
421
    }
×
422
}
423

424
impl<'a> ToSchema<'a> for OgrMetaData {
425
    fn schema() -> (&'a str, utoipa::openapi::RefOr<utoipa::openapi::Schema>) {
×
426
        use utoipa::openapi::*;
×
427
        (
×
428
            "MockMetaData",
×
429
            ObjectBuilder::new()
×
430
                .property("loadingInfo", Ref::from_schema_name("OgrSourceDataset"))
×
431
                .required("loadingInfo")
×
432
                .property(
×
433
                    "resultDescriptor",
×
434
                    Ref::from_schema_name("VectorResultDescriptor"),
×
435
                )
×
436
                .required("resultDescriptor")
×
437
                .into(),
×
438
        )
×
439
    }
×
440
}
441

442
#[derive(PartialEq, Serialize, Deserialize, Debug, Clone, ToSchema)]
×
443
#[serde(rename_all = "camelCase")]
444
pub struct GdalMetaDataStatic {
445
    pub time: Option<TimeInterval>,
446
    pub params: GdalDatasetParameters,
447
    pub result_descriptor: RasterResultDescriptor,
448
}
449

450
impl From<geoengine_operators::source::GdalMetaDataStatic> for GdalMetaDataStatic {
451
    fn from(value: geoengine_operators::source::GdalMetaDataStatic) -> Self {
×
452
        Self {
×
453
            time: value.time.map(Into::into),
×
454
            params: value.params.into(),
×
455
            result_descriptor: value.result_descriptor.into(),
×
456
        }
×
457
    }
×
458
}
459

460
impl From<GdalMetaDataStatic> for geoengine_operators::source::GdalMetaDataStatic {
461
    fn from(value: GdalMetaDataStatic) -> Self {
1✔
462
        Self {
1✔
463
            time: value.time.map(Into::into),
1✔
464
            params: value.params.into(),
1✔
465
            result_descriptor: value.result_descriptor.into(),
1✔
466
        }
1✔
467
    }
1✔
468
}
469

470
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, ToSchema)]
60✔
471
#[serde(rename_all = "camelCase")]
472
pub struct OgrSourceDataset {
473
    #[schema(value_type = String)]
474
    pub file_name: PathBuf,
475
    pub layer_name: String,
476
    pub data_type: Option<VectorDataType>,
477
    #[serde(default)]
478
    pub time: OgrSourceDatasetTimeType,
479
    pub default_geometry: Option<TypedGeometry>,
480
    pub columns: Option<OgrSourceColumnSpec>,
481
    #[serde(default)]
482
    pub force_ogr_time_filter: bool,
483
    #[serde(default)]
484
    pub force_ogr_spatial_filter: bool,
485
    pub on_error: OgrSourceErrorSpec,
486
    pub sql_query: Option<String>,
487
    pub attribute_query: Option<String>,
488
}
489

490
impl From<geoengine_operators::source::OgrSourceDataset> for OgrSourceDataset {
491
    fn from(value: geoengine_operators::source::OgrSourceDataset) -> Self {
1✔
492
        Self {
1✔
493
            file_name: value.file_name,
1✔
494
            layer_name: value.layer_name,
1✔
495
            data_type: value.data_type.map(Into::into),
1✔
496
            time: value.time.into(),
1✔
497
            default_geometry: value.default_geometry.map(Into::into),
1✔
498
            columns: value.columns.map(Into::into),
1✔
499
            force_ogr_time_filter: value.force_ogr_time_filter,
1✔
500
            force_ogr_spatial_filter: value.force_ogr_spatial_filter,
1✔
501
            on_error: value.on_error.into(),
1✔
502
            sql_query: value.sql_query,
1✔
503
            attribute_query: value.attribute_query,
1✔
504
        }
1✔
505
    }
1✔
506
}
507

508
impl From<OgrSourceDataset> for geoengine_operators::source::OgrSourceDataset {
509
    fn from(value: OgrSourceDataset) -> Self {
4✔
510
        Self {
4✔
511
            file_name: value.file_name,
4✔
512
            layer_name: value.layer_name,
4✔
513
            data_type: value.data_type.map(Into::into),
4✔
514
            time: value.time.into(),
4✔
515
            default_geometry: value.default_geometry.map(Into::into),
4✔
516
            columns: value.columns.map(Into::into),
4✔
517
            force_ogr_time_filter: value.force_ogr_time_filter,
4✔
518
            force_ogr_spatial_filter: value.force_ogr_spatial_filter,
4✔
519
            on_error: value.on_error.into(),
4✔
520
            sql_query: value.sql_query,
4✔
521
            attribute_query: value.attribute_query,
4✔
522
        }
4✔
523
    }
4✔
524
}
525

526
#[derive(Deserialize, Serialize, PartialEq, Eq, Clone, Debug, ToSchema)]
×
527
#[serde(tag = "format")]
528
#[serde(rename_all = "camelCase")]
529
pub enum OgrSourceTimeFormat {
530
    #[serde(rename_all = "camelCase")]
531
    Custom {
532
        custom_format: DateTimeParseFormat,
533
    },
534
    #[serde(rename_all = "camelCase")]
535
    UnixTimeStamp {
536
        timestamp_type: UnixTimeStampType,
537
        #[serde(skip)]
538
        #[serde(default = "DateTimeParseFormat::unix")]
539
        fmt: DateTimeParseFormat,
540
    },
541
    Auto,
542
}
543

544
impl From<geoengine_operators::source::OgrSourceTimeFormat> for OgrSourceTimeFormat {
545
    fn from(value: geoengine_operators::source::OgrSourceTimeFormat) -> Self {
×
546
        match value {
×
547
            geoengine_operators::source::OgrSourceTimeFormat::Custom { custom_format } => {
×
548
                Self::Custom {
×
549
                    custom_format: custom_format.into(),
×
550
                }
×
551
            }
552
            geoengine_operators::source::OgrSourceTimeFormat::UnixTimeStamp {
553
                timestamp_type,
×
554
                fmt,
×
555
            } => Self::UnixTimeStamp {
×
556
                timestamp_type: timestamp_type.into(),
×
557
                fmt: fmt.into(),
×
558
            },
×
559
            geoengine_operators::source::OgrSourceTimeFormat::Auto => Self::Auto,
×
560
        }
561
    }
×
562
}
563

564
impl From<OgrSourceTimeFormat> for geoengine_operators::source::OgrSourceTimeFormat {
565
    fn from(value: OgrSourceTimeFormat) -> Self {
×
566
        match value {
×
567
            OgrSourceTimeFormat::Custom { custom_format } => Self::Custom {
×
568
                custom_format: custom_format.into(),
×
569
            },
×
570
            OgrSourceTimeFormat::UnixTimeStamp {
571
                timestamp_type,
×
572
                fmt,
×
573
            } => Self::UnixTimeStamp {
×
574
                timestamp_type: timestamp_type.into(),
×
575
                fmt: fmt.into(),
×
576
            },
×
577
            OgrSourceTimeFormat::Auto => Self::Auto,
×
578
        }
579
    }
×
580
}
581

582
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, ToSchema)]
×
583
#[serde(rename_all = "camelCase")]
584
pub enum UnixTimeStampType {
585
    EpochSeconds,
586
    EpochMilliseconds,
587
}
588

589
impl From<geoengine_operators::source::UnixTimeStampType> for UnixTimeStampType {
590
    fn from(value: geoengine_operators::source::UnixTimeStampType) -> Self {
×
591
        match value {
×
592
            geoengine_operators::source::UnixTimeStampType::EpochSeconds => Self::EpochSeconds,
×
593
            geoengine_operators::source::UnixTimeStampType::EpochMilliseconds => {
594
                Self::EpochMilliseconds
×
595
            }
596
        }
597
    }
×
598
}
599

600
impl From<UnixTimeStampType> for geoengine_operators::source::UnixTimeStampType {
601
    fn from(value: UnixTimeStampType) -> Self {
×
602
        match value {
×
603
            UnixTimeStampType::EpochSeconds => Self::EpochSeconds,
×
604
            UnixTimeStampType::EpochMilliseconds => Self::EpochMilliseconds,
×
605
        }
606
    }
×
607
}
608

609
#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize, Serialize, ToSchema)]
8✔
610
#[serde(rename_all = "lowercase")]
611
pub enum OgrSourceErrorSpec {
612
    Ignore,
613
    Abort,
614
}
615

616
impl From<geoengine_operators::source::OgrSourceErrorSpec> for OgrSourceErrorSpec {
617
    fn from(value: geoengine_operators::source::OgrSourceErrorSpec) -> Self {
1✔
618
        match value {
1✔
619
            geoengine_operators::source::OgrSourceErrorSpec::Ignore => Self::Ignore,
1✔
620
            geoengine_operators::source::OgrSourceErrorSpec::Abort => Self::Abort,
×
621
        }
622
    }
1✔
623
}
624

625
impl From<OgrSourceErrorSpec> for geoengine_operators::source::OgrSourceErrorSpec {
626
    fn from(value: OgrSourceErrorSpec) -> Self {
4✔
627
        match value {
4✔
628
            OgrSourceErrorSpec::Ignore => Self::Ignore,
4✔
629
            OgrSourceErrorSpec::Abort => Self::Abort,
×
630
        }
631
    }
4✔
632
}
633

634
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, ToSchema)]
8✔
635
#[serde(rename_all = "camelCase", tag = "type")]
636
pub enum OgrSourceDatasetTimeType {
637
    None,
638
    #[serde(rename_all = "camelCase")]
639
    Start {
640
        start_field: String,
641
        start_format: OgrSourceTimeFormat,
642
        duration: OgrSourceDurationSpec,
643
    },
644
    #[serde(rename = "start+end")]
645
    #[serde(rename_all = "camelCase")]
646
    StartEnd {
647
        start_field: String,
648
        start_format: OgrSourceTimeFormat,
649
        end_field: String,
650
        end_format: OgrSourceTimeFormat,
651
    },
652
    #[serde(rename = "start+duration")]
653
    #[serde(rename_all = "camelCase")]
654
    StartDuration {
655
        start_field: String,
656
        start_format: OgrSourceTimeFormat,
657
        duration_field: String,
658
    },
659
}
660

661
impl From<geoengine_operators::source::OgrSourceDatasetTimeType> for OgrSourceDatasetTimeType {
662
    fn from(value: geoengine_operators::source::OgrSourceDatasetTimeType) -> Self {
1✔
663
        match value {
1✔
664
            geoengine_operators::source::OgrSourceDatasetTimeType::None => Self::None,
1✔
665
            geoengine_operators::source::OgrSourceDatasetTimeType::Start {
666
                start_field,
×
667
                start_format,
×
668
                duration,
×
669
            } => Self::Start {
×
670
                start_field,
×
671
                start_format: start_format.into(),
×
672
                duration: duration.into(),
×
673
            },
×
674
            geoengine_operators::source::OgrSourceDatasetTimeType::StartEnd {
675
                start_field,
×
676
                start_format,
×
677
                end_field,
×
678
                end_format,
×
679
            } => Self::StartEnd {
×
680
                start_field,
×
681
                start_format: start_format.into(),
×
682
                end_field,
×
683
                end_format: end_format.into(),
×
684
            },
×
685
            geoengine_operators::source::OgrSourceDatasetTimeType::StartDuration {
686
                start_field,
×
687
                start_format,
×
688
                duration_field,
×
689
            } => Self::StartDuration {
×
690
                start_field,
×
691
                start_format: start_format.into(),
×
692
                duration_field,
×
693
            },
×
694
        }
695
    }
1✔
696
}
697

698
impl From<OgrSourceDatasetTimeType> for geoengine_operators::source::OgrSourceDatasetTimeType {
699
    fn from(value: OgrSourceDatasetTimeType) -> Self {
4✔
700
        match value {
4✔
701
            OgrSourceDatasetTimeType::None => Self::None,
4✔
702
            OgrSourceDatasetTimeType::Start {
703
                start_field,
×
704
                start_format,
×
705
                duration,
×
706
            } => Self::Start {
×
707
                start_field,
×
708
                start_format: start_format.into(),
×
709
                duration: duration.into(),
×
710
            },
×
711
            OgrSourceDatasetTimeType::StartEnd {
712
                start_field,
×
713
                start_format,
×
714
                end_field,
×
715
                end_format,
×
716
            } => Self::StartEnd {
×
717
                start_field,
×
718
                start_format: start_format.into(),
×
719
                end_field,
×
720
                end_format: end_format.into(),
×
721
            },
×
722
            OgrSourceDatasetTimeType::StartDuration {
723
                start_field,
×
724
                start_format,
×
725
                duration_field,
×
726
            } => Self::StartDuration {
×
727
                start_field,
×
728
                start_format: start_format.into(),
×
729
                duration_field,
×
730
            },
×
731
        }
732
    }
4✔
733
}
734

735
/// If no time is specified, expect to parse none
736
impl Default for OgrSourceDatasetTimeType {
737
    fn default() -> Self {
×
738
        Self::None
×
739
    }
×
740
}
741

742
#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize, Serialize, ToSchema)]
×
743
#[serde(rename_all = "camelCase", tag = "type")]
744
pub enum OgrSourceDurationSpec {
745
    Infinite,
746
    Zero,
747
    Value(TimeStep),
748
}
749

750
impl From<geoengine_operators::source::OgrSourceDurationSpec> for OgrSourceDurationSpec {
751
    fn from(value: geoengine_operators::source::OgrSourceDurationSpec) -> Self {
×
752
        match value {
×
753
            geoengine_operators::source::OgrSourceDurationSpec::Infinite => Self::Infinite,
×
754
            geoengine_operators::source::OgrSourceDurationSpec::Zero => Self::Zero,
×
755
            geoengine_operators::source::OgrSourceDurationSpec::Value(v) => Self::Value(v.into()),
×
756
        }
757
    }
×
758
}
759

760
impl From<OgrSourceDurationSpec> for geoengine_operators::source::OgrSourceDurationSpec {
761
    fn from(value: OgrSourceDurationSpec) -> Self {
×
762
        match value {
×
763
            OgrSourceDurationSpec::Infinite => Self::Infinite,
×
764
            OgrSourceDurationSpec::Zero => Self::Zero,
×
765
            OgrSourceDurationSpec::Value(v) => Self::Value(v.into()),
×
766
        }
767
    }
×
768
}
769

770
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)]
×
771
pub enum TypedGeometry {
772
    Data(NoGeometry),
773
    MultiPoint(MultiPoint),
774
    MultiLineString(MultiLineString),
775
    MultiPolygon(MultiPolygon),
776
}
777

778
impl From<geoengine_datatypes::primitives::TypedGeometry> for TypedGeometry {
779
    fn from(value: geoengine_datatypes::primitives::TypedGeometry) -> Self {
×
780
        match value {
×
781
            geoengine_datatypes::primitives::TypedGeometry::Data(x) => Self::Data(x.into()),
×
782
            geoengine_datatypes::primitives::TypedGeometry::MultiPoint(x) => {
×
783
                Self::MultiPoint(x.into())
×
784
            }
785
            geoengine_datatypes::primitives::TypedGeometry::MultiLineString(x) => {
×
786
                Self::MultiLineString(x.into())
×
787
            }
788
            geoengine_datatypes::primitives::TypedGeometry::MultiPolygon(x) => {
×
789
                Self::MultiPolygon(x.into())
×
790
            }
791
        }
792
    }
×
793
}
794

795
impl From<TypedGeometry> for geoengine_datatypes::primitives::TypedGeometry {
796
    fn from(value: TypedGeometry) -> Self {
×
797
        match value {
×
798
            TypedGeometry::Data(x) => Self::Data(x.into()),
×
799
            TypedGeometry::MultiPoint(x) => Self::MultiPoint(x.into()),
×
800
            TypedGeometry::MultiLineString(x) => Self::MultiLineString(x.into()),
×
801
            TypedGeometry::MultiPolygon(x) => Self::MultiPolygon(x.into()),
×
802
        }
803
    }
×
804
}
805

806
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, ToSchema)]
60✔
807
#[serde(rename_all = "camelCase")]
808
pub struct OgrSourceColumnSpec {
809
    pub format_specifics: Option<FormatSpecifics>,
810
    pub x: String,
811
    pub y: Option<String>,
812
    #[serde(default)]
813
    pub int: Vec<String>,
814
    #[serde(default)]
815
    pub float: Vec<String>,
816
    #[serde(default)]
817
    pub text: Vec<String>,
818
    #[serde(default)]
819
    pub bool: Vec<String>,
820
    #[serde(default)]
821
    pub datetime: Vec<String>,
822
    pub rename: Option<HashMap<String, String>>,
823
}
824

825
impl From<geoengine_operators::source::OgrSourceColumnSpec> for OgrSourceColumnSpec {
826
    fn from(value: geoengine_operators::source::OgrSourceColumnSpec) -> Self {
1✔
827
        Self {
1✔
828
            format_specifics: value.format_specifics.map(Into::into),
1✔
829
            x: value.x,
1✔
830
            y: value.y,
1✔
831
            int: value.int,
1✔
832
            float: value.float,
1✔
833
            text: value.text,
1✔
834
            bool: value.bool,
1✔
835
            datetime: value.datetime,
1✔
836
            rename: value.rename,
1✔
837
        }
1✔
838
    }
1✔
839
}
840

841
impl From<OgrSourceColumnSpec> for geoengine_operators::source::OgrSourceColumnSpec {
842
    fn from(value: OgrSourceColumnSpec) -> Self {
4✔
843
        Self {
4✔
844
            format_specifics: value.format_specifics.map(Into::into),
4✔
845
            x: value.x,
4✔
846
            y: value.y,
4✔
847
            int: value.int,
4✔
848
            float: value.float,
4✔
849
            text: value.text,
4✔
850
            bool: value.bool,
4✔
851
            datetime: value.datetime,
4✔
852
            rename: value.rename,
4✔
853
        }
4✔
854
    }
4✔
855
}
856

857
#[derive(Serialize, Deserialize, Debug, Clone, ToSchema)]
44✔
858
#[serde(rename_all = "camelCase")]
859
pub struct GdalMetaDataRegular {
860
    pub result_descriptor: RasterResultDescriptor,
861
    pub params: GdalDatasetParameters,
862
    pub time_placeholders: HashMap<String, GdalSourceTimePlaceholder>,
863
    pub data_time: TimeInterval,
864
    pub step: TimeStep,
865
}
866

867
impl From<geoengine_operators::source::GdalMetaDataRegular> for GdalMetaDataRegular {
868
    fn from(value: geoengine_operators::source::GdalMetaDataRegular) -> Self {
4✔
869
        Self {
4✔
870
            result_descriptor: value.result_descriptor.into(),
4✔
871
            params: value.params.into(),
4✔
872
            time_placeholders: value
4✔
873
                .time_placeholders
4✔
874
                .into_iter()
4✔
875
                .map(|(k, v)| (k, v.into()))
4✔
876
                .collect(),
4✔
877
            data_time: value.data_time.into(),
4✔
878
            step: value.step.into(),
4✔
879
        }
4✔
880
    }
4✔
881
}
882

883
impl From<GdalMetaDataRegular> for geoengine_operators::source::GdalMetaDataRegular {
884
    fn from(value: GdalMetaDataRegular) -> Self {
4✔
885
        Self {
4✔
886
            result_descriptor: value.result_descriptor.into(),
4✔
887
            params: value.params.into(),
4✔
888
            time_placeholders: value
4✔
889
                .time_placeholders
4✔
890
                .into_iter()
4✔
891
                .map(|(k, v)| (k, v.into()))
4✔
892
                .collect(),
4✔
893
            data_time: value.data_time.into(),
4✔
894
            step: value.step.into(),
4✔
895
        }
4✔
896
    }
4✔
897
}
898

899
pub type GdalConfigOption = StringPair;
900

901
/// Parameters for loading data using Gdal
902
#[derive(PartialEq, Serialize, Deserialize, Debug, Clone, ToSchema)]
92✔
903
#[serde(rename_all = "camelCase")]
904
pub struct GdalDatasetParameters {
905
    #[schema(value_type = String)]
906
    pub file_path: PathBuf,
907
    pub rasterband_channel: usize,
908
    pub geo_transform: GdalDatasetGeoTransform, // TODO: discuss if we need this at all
909
    pub width: usize,
910
    pub height: usize,
911
    pub file_not_found_handling: FileNotFoundHandling,
912
    #[serde(default)]
913
    //#[serde(with = "float_option_with_nan")]
914
    pub no_data_value: Option<f64>,
915
    pub properties_mapping: Option<Vec<GdalMetadataMapping>>,
916
    // Dataset open option as strings, e.g. `vec!["UserPwd=geoengine:pwd".to_owned(), "HttpAuth=BASIC".to_owned()]`
917
    pub gdal_open_options: Option<Vec<String>>,
918
    // Configs as key, value pairs that will be set as thread local config options, e.g.
919
    // `vec!["AWS_REGION".to_owned(), "eu-central-1".to_owned()]` and unset afterwards
920
    // TODO: validate the config options: only allow specific keys and specific values
921
    pub gdal_config_options: Option<Vec<GdalConfigOption>>,
922
    #[serde(default)]
923
    pub allow_alphaband_as_mask: bool,
924
}
925

926
impl From<geoengine_operators::source::GdalDatasetParameters> for GdalDatasetParameters {
927
    fn from(value: geoengine_operators::source::GdalDatasetParameters) -> Self {
4✔
928
        Self {
4✔
929
            file_path: value.file_path,
4✔
930
            rasterband_channel: value.rasterband_channel,
4✔
931
            geo_transform: value.geo_transform.into(),
4✔
932
            width: value.width,
4✔
933
            height: value.height,
4✔
934
            file_not_found_handling: value.file_not_found_handling.into(),
4✔
935
            no_data_value: value.no_data_value,
4✔
936
            properties_mapping: value
4✔
937
                .properties_mapping
4✔
938
                .map(|x| x.into_iter().map(Into::into).collect()),
4✔
939
            gdal_open_options: value.gdal_open_options,
4✔
940
            gdal_config_options: value
4✔
941
                .gdal_config_options
4✔
942
                .map(|x| x.into_iter().map(Into::into).collect()),
4✔
943
            allow_alphaband_as_mask: value.allow_alphaband_as_mask,
4✔
944
        }
4✔
945
    }
4✔
946
}
947

948
impl From<GdalDatasetParameters> for geoengine_operators::source::GdalDatasetParameters {
949
    fn from(value: GdalDatasetParameters) -> Self {
5✔
950
        Self {
5✔
951
            file_path: value.file_path,
5✔
952
            rasterband_channel: value.rasterband_channel,
5✔
953
            geo_transform: value.geo_transform.into(),
5✔
954
            width: value.width,
5✔
955
            height: value.height,
5✔
956
            file_not_found_handling: value.file_not_found_handling.into(),
5✔
957
            no_data_value: value.no_data_value,
5✔
958
            properties_mapping: value
5✔
959
                .properties_mapping
5✔
960
                .map(|x| x.into_iter().map(Into::into).collect()),
5✔
961
            gdal_open_options: value.gdal_open_options,
5✔
962
            gdal_config_options: value
5✔
963
                .gdal_config_options
5✔
964
                .map(|x| x.into_iter().map(Into::into).collect()),
5✔
965
            allow_alphaband_as_mask: value.allow_alphaband_as_mask,
5✔
966
            retry: None,
5✔
967
        }
5✔
968
    }
5✔
969
}
970

971
#[derive(Serialize, Deserialize, Debug, Clone, ToSchema)]
20✔
972
pub struct GdalSourceTimePlaceholder {
973
    pub format: DateTimeParseFormat,
974
    pub reference: TimeReference,
975
}
976

977
impl From<geoengine_operators::source::GdalSourceTimePlaceholder> for GdalSourceTimePlaceholder {
978
    fn from(value: geoengine_operators::source::GdalSourceTimePlaceholder) -> Self {
4✔
979
        Self {
4✔
980
            format: value.format.into(),
4✔
981
            reference: value.reference.into(),
4✔
982
        }
4✔
983
    }
4✔
984
}
985

986
impl From<GdalSourceTimePlaceholder> for geoengine_operators::source::GdalSourceTimePlaceholder {
987
    fn from(value: GdalSourceTimePlaceholder) -> Self {
4✔
988
        Self {
4✔
989
            format: value.format.into(),
4✔
990
            reference: value.reference.into(),
4✔
991
        }
4✔
992
    }
4✔
993
}
994

995
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, ToSchema)]
28✔
996
#[serde(rename_all = "camelCase")]
997
pub struct GdalDatasetGeoTransform {
998
    pub origin_coordinate: Coordinate2D,
999
    pub x_pixel_size: f64,
1000
    pub y_pixel_size: f64,
1001
}
1002

1003
impl From<geoengine_operators::source::GdalDatasetGeoTransform> for GdalDatasetGeoTransform {
1004
    fn from(value: geoengine_operators::source::GdalDatasetGeoTransform) -> Self {
4✔
1005
        Self {
4✔
1006
            origin_coordinate: value.origin_coordinate.into(),
4✔
1007
            x_pixel_size: value.x_pixel_size,
4✔
1008
            y_pixel_size: value.y_pixel_size,
4✔
1009
        }
4✔
1010
    }
4✔
1011
}
1012

1013
impl From<GdalDatasetGeoTransform> for geoengine_operators::source::GdalDatasetGeoTransform {
1014
    fn from(value: GdalDatasetGeoTransform) -> Self {
5✔
1015
        Self {
5✔
1016
            origin_coordinate: value.origin_coordinate.into(),
5✔
1017
            x_pixel_size: value.x_pixel_size,
5✔
1018
            y_pixel_size: value.y_pixel_size,
5✔
1019
        }
5✔
1020
    }
5✔
1021
}
1022

1023
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, ToSchema)]
8✔
1024
pub enum FileNotFoundHandling {
1025
    NoData, // output tiles filled with nodata
1026
    Error,  // return error tile
1027
}
1028

1029
impl From<geoengine_operators::source::FileNotFoundHandling> for FileNotFoundHandling {
1030
    fn from(value: geoengine_operators::source::FileNotFoundHandling) -> Self {
4✔
1031
        match value {
4✔
1032
            geoengine_operators::source::FileNotFoundHandling::NoData => Self::NoData,
4✔
1033
            geoengine_operators::source::FileNotFoundHandling::Error => Self::Error,
×
1034
        }
1035
    }
4✔
1036
}
1037

1038
impl From<FileNotFoundHandling> for geoengine_operators::source::FileNotFoundHandling {
1039
    fn from(value: FileNotFoundHandling) -> Self {
5✔
1040
        match value {
5✔
1041
            FileNotFoundHandling::NoData => Self::NoData,
5✔
1042
            FileNotFoundHandling::Error => Self::Error,
×
1043
        }
1044
    }
5✔
1045
}
1046

1047
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
×
1048
pub struct GdalMetadataMapping {
1049
    pub source_key: RasterPropertiesKey,
1050
    pub target_key: RasterPropertiesKey,
1051
    pub target_type: RasterPropertiesEntryType,
1052
}
1053

1054
impl From<geoengine_operators::source::GdalMetadataMapping> for GdalMetadataMapping {
1055
    fn from(value: geoengine_operators::source::GdalMetadataMapping) -> Self {
×
1056
        Self {
×
1057
            source_key: value.source_key.into(),
×
1058
            target_key: value.target_key.into(),
×
1059
            target_type: value.target_type.into(),
×
1060
        }
×
1061
    }
×
1062
}
1063

1064
impl From<GdalMetadataMapping> for geoengine_operators::source::GdalMetadataMapping {
1065
    fn from(value: GdalMetadataMapping) -> Self {
×
1066
        Self {
×
1067
            source_key: value.source_key.into(),
×
1068
            target_key: value.target_key.into(),
×
1069
            target_type: value.target_type.into(),
×
1070
        }
×
1071
    }
×
1072
}
1073

1074
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, ToSchema)]
8✔
1075
#[serde(rename_all = "camelCase")]
1076
pub enum TimeReference {
1077
    Start,
1078
    End,
1079
}
1080

1081
impl From<geoengine_operators::source::TimeReference> for TimeReference {
1082
    fn from(value: geoengine_operators::source::TimeReference) -> Self {
4✔
1083
        match value {
4✔
1084
            geoengine_operators::source::TimeReference::Start => Self::Start,
4✔
1085
            geoengine_operators::source::TimeReference::End => Self::End,
×
1086
        }
1087
    }
4✔
1088
}
1089

1090
impl From<TimeReference> for geoengine_operators::source::TimeReference {
1091
    fn from(value: TimeReference) -> Self {
4✔
1092
        match value {
4✔
1093
            TimeReference::Start => Self::Start,
4✔
1094
            TimeReference::End => Self::End,
×
1095
        }
1096
    }
4✔
1097
}
1098

1099
/// Meta data for 4D `NetCDF` CF datasets
1100
#[derive(PartialEq, Serialize, Deserialize, Debug, Clone, ToSchema)]
×
1101
#[serde(rename_all = "camelCase")]
1102
pub struct GdalMetadataNetCdfCf {
1103
    pub result_descriptor: RasterResultDescriptor,
1104
    pub params: GdalDatasetParameters,
1105
    pub start: TimeInstance,
1106
    /// We use the end to specify the last, non-inclusive valid time point.
1107
    /// Queries behind this point return no data.
1108
    /// TODO: Alternatively, we could think about using the number of possible time steps in the future.
1109
    pub end: TimeInstance,
1110
    pub step: TimeStep,
1111
    /// A band offset specifies the first band index to use for the first point in time.
1112
    /// All other time steps are added to this offset.
1113
    pub band_offset: usize,
1114
}
1115

1116
impl From<geoengine_operators::source::GdalMetadataNetCdfCf> for GdalMetadataNetCdfCf {
1117
    fn from(value: geoengine_operators::source::GdalMetadataNetCdfCf) -> Self {
×
1118
        Self {
×
1119
            result_descriptor: value.result_descriptor.into(),
×
1120
            params: value.params.into(),
×
1121
            start: value.start.into(),
×
1122
            end: value.end.into(),
×
1123
            step: value.step.into(),
×
1124
            band_offset: value.band_offset,
×
1125
        }
×
1126
    }
×
1127
}
1128

1129
impl From<GdalMetadataNetCdfCf> for geoengine_operators::source::GdalMetadataNetCdfCf {
1130
    fn from(value: GdalMetadataNetCdfCf) -> Self {
×
1131
        Self {
×
1132
            result_descriptor: value.result_descriptor.into(),
×
1133
            params: value.params.into(),
×
1134
            start: value.start.into(),
×
1135
            end: value.end.into(),
×
1136
            step: value.step.into(),
×
1137
            band_offset: value.band_offset,
×
1138
        }
×
1139
    }
×
1140
}
1141

1142
#[derive(PartialEq, Serialize, Deserialize, Debug, Clone, ToSchema)]
×
1143
#[serde(rename_all = "camelCase")]
1144
pub struct GdalMetaDataList {
1145
    pub result_descriptor: RasterResultDescriptor,
1146
    pub params: Vec<GdalLoadingInfoTemporalSlice>,
1147
}
1148

1149
impl From<geoengine_operators::source::GdalMetaDataList> for GdalMetaDataList {
1150
    fn from(value: geoengine_operators::source::GdalMetaDataList) -> Self {
×
1151
        Self {
×
1152
            result_descriptor: value.result_descriptor.into(),
×
1153
            params: value.params.into_iter().map(Into::into).collect(),
×
1154
        }
×
1155
    }
×
1156
}
1157

1158
impl From<GdalMetaDataList> for geoengine_operators::source::GdalMetaDataList {
1159
    fn from(value: GdalMetaDataList) -> Self {
×
1160
        Self {
×
1161
            result_descriptor: value.result_descriptor.into(),
×
1162
            params: value.params.into_iter().map(Into::into).collect(),
×
1163
        }
×
1164
    }
×
1165
}
1166

1167
/// one temporal slice of the dataset that requires reading from exactly one Gdal dataset
1168
#[derive(PartialEq, Serialize, Deserialize, Debug, Clone, ToSchema)]
×
1169
#[serde(rename_all = "camelCase")]
1170
pub struct GdalLoadingInfoTemporalSlice {
1171
    pub time: TimeInterval,
1172
    pub params: Option<GdalDatasetParameters>,
1173
}
1174

1175
impl From<geoengine_operators::source::GdalLoadingInfoTemporalSlice>
1176
    for GdalLoadingInfoTemporalSlice
1177
{
1178
    fn from(value: geoengine_operators::source::GdalLoadingInfoTemporalSlice) -> Self {
×
1179
        Self {
×
1180
            time: value.time.into(),
×
1181
            params: value.params.map(Into::into),
×
1182
        }
×
1183
    }
×
1184
}
1185

1186
impl From<GdalLoadingInfoTemporalSlice>
1187
    for geoengine_operators::source::GdalLoadingInfoTemporalSlice
1188
{
1189
    fn from(value: GdalLoadingInfoTemporalSlice) -> Self {
×
1190
        Self {
×
1191
            time: value.time.into(),
×
1192
            params: value.params.map(Into::into),
×
1193
        }
×
1194
    }
×
1195
}
1196

1197
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, ToSchema)]
×
1198
#[serde(rename_all = "lowercase")]
1199
pub enum CsvHeader {
1200
    Yes,
1201
    No,
1202
    Auto,
1203
}
1204

1205
impl From<geoengine_operators::source::CsvHeader> for CsvHeader {
1206
    fn from(value: geoengine_operators::source::CsvHeader) -> Self {
×
1207
        match value {
×
1208
            geoengine_operators::source::CsvHeader::Yes => Self::Yes,
×
1209
            geoengine_operators::source::CsvHeader::No => Self::No,
×
1210
            geoengine_operators::source::CsvHeader::Auto => Self::Auto,
×
1211
        }
1212
    }
×
1213
}
1214

1215
impl From<CsvHeader> for geoengine_operators::source::CsvHeader {
1216
    fn from(value: CsvHeader) -> Self {
×
1217
        match value {
×
1218
            CsvHeader::Yes => Self::Yes,
×
1219
            CsvHeader::No => Self::No,
×
1220
            CsvHeader::Auto => Self::Auto,
×
1221
        }
1222
    }
×
1223
}
1224

1225
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, ToSchema)]
×
1226
#[serde(rename_all = "camelCase")]
1227
pub enum FormatSpecifics {
1228
    Csv { header: CsvHeader },
1229
}
1230

1231
impl From<geoengine_operators::source::FormatSpecifics> for FormatSpecifics {
1232
    fn from(value: geoengine_operators::source::FormatSpecifics) -> Self {
×
1233
        match value {
×
1234
            geoengine_operators::source::FormatSpecifics::Csv { header } => Self::Csv {
×
1235
                header: header.into(),
×
1236
            },
×
1237
        }
×
1238
    }
×
1239
}
1240

1241
impl From<FormatSpecifics> for geoengine_operators::source::FormatSpecifics {
1242
    fn from(value: FormatSpecifics) -> Self {
×
1243
        match value {
×
1244
            FormatSpecifics::Csv { header } => Self::Csv {
×
1245
                header: header.into(),
×
1246
            },
×
1247
        }
×
1248
    }
×
1249
}
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