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

geo-engine / geoengine / 5740825225

02 Aug 2023 03:32PM UTC coverage: 88.958% (+0.05%) from 88.913%
5740825225

push

github

web-flow
Merge pull request #844 from geo-engine/pg-symbology-mapping

Pg symbology mapping

610 of 610 new or added lines in 10 files covered. (100.0%)

106476 of 119693 relevant lines covered (88.96%)

60487.94 hits per line

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

97.85
/services/src/api/model/db_types.rs
1
use ordered_float::NotNan;
2
use postgres_types::{FromSql, ToSql};
3

4
use crate::{
5
    error::Error,
6
    projects::{
7
        ColorParam, DerivedColor, DerivedNumber, LineSymbology, NumberParam, PointSymbology,
8
        PolygonSymbology, RasterSymbology, Symbology,
9
    },
10
};
11

12
use super::datatypes::{
13
    Breakpoint, Colorizer, DefaultColors, LinearGradient, LogarithmicGradient, OverUnderColors,
14
    Palette, RgbaColor,
15
};
16

17
#[derive(Debug, ToSql, FromSql)]
4,792✔
18
#[postgres(name = "DefaultColors")]
19
pub struct DefaultColorsDbType {
20
    pub default_color: Option<RgbaColor>,
21
    pub over_color: Option<RgbaColor>,
22
    pub under_color: Option<RgbaColor>,
23
}
24

25
impl From<&DefaultColors> for DefaultColorsDbType {
26
    fn from(value: &DefaultColors) -> Self {
15✔
27
        match value {
15✔
28
            DefaultColors::DefaultColor { default_color } => Self {
1✔
29
                default_color: Some(*default_color),
1✔
30
                over_color: None,
1✔
31
                under_color: None,
1✔
32
            },
1✔
33
            DefaultColors::OverUnder(over_under) => Self {
14✔
34
                default_color: None,
14✔
35
                over_color: Some(over_under.over_color),
14✔
36
                under_color: Some(over_under.under_color),
14✔
37
            },
14✔
38
        }
39
    }
15✔
40
}
41

42
impl TryFrom<DefaultColorsDbType> for DefaultColors {
43
    type Error = Error;
44

45
    fn try_from(value: DefaultColorsDbType) -> Result<Self, Self::Error> {
46
        match (value.default_color, value.over_color, value.under_color) {
13✔
47
            (Some(default_color), None, None) => Ok(Self::DefaultColor { default_color }),
1✔
48
            (None, Some(over_color), Some(under_color)) => Ok(Self::OverUnder(OverUnderColors {
12✔
49
                over_color,
12✔
50
                under_color,
12✔
51
            })),
12✔
52
            _ => Err(Error::UnexpectedInvalidDbTypeConversion),
×
53
        }
54
    }
13✔
55
}
56

57
#[derive(Debug, ToSql, FromSql)]
7,164✔
58
#[postgres(name = "Colorizer")]
59
pub struct ColorizerDbType {
60
    r#type: ColorizerTypeDbType,
61
    breakpoints: Option<Vec<Breakpoint>>,
62
    no_data_color: Option<RgbaColor>,
63
    color_fields: Option<DefaultColorsDbType>,
64
    default_color: Option<RgbaColor>,
65
}
66

67
#[derive(Debug, PartialEq, ToSql, FromSql)]
5,990✔
68
// TODO: use #[postgres(rename_all = "camelCase")]
69
#[postgres(name = "ColorizerType")]
70
pub enum ColorizerTypeDbType {
71
    LinearGradient,
72
    LogarithmicGradient,
73
    Palette,
74
    Rgba,
75
}
76

77
impl From<&Colorizer> for ColorizerDbType {
78
    fn from(value: &Colorizer) -> Self {
18✔
79
        match value {
18✔
80
            Colorizer::LinearGradient(gradient) => ColorizerDbType {
12✔
81
                r#type: ColorizerTypeDbType::LinearGradient,
12✔
82
                breakpoints: Some(gradient.breakpoints.clone()),
12✔
83
                no_data_color: Some(gradient.no_data_color),
12✔
84
                color_fields: Some((&gradient.color_fields).into()),
12✔
85
                default_color: None,
12✔
86
            },
12✔
87
            Colorizer::LogarithmicGradient(gradient) => ColorizerDbType {
1✔
88
                r#type: ColorizerTypeDbType::LogarithmicGradient,
1✔
89
                breakpoints: Some(gradient.breakpoints.clone()),
1✔
90
                no_data_color: Some(gradient.no_data_color),
1✔
91
                color_fields: Some((&gradient.color_fields).into()),
1✔
92
                default_color: None,
1✔
93
            },
1✔
94
            Colorizer::Palette {
95
                colors,
1✔
96
                no_data_color,
1✔
97
                default_color,
1✔
98
            } => ColorizerDbType {
1✔
99
                r#type: ColorizerTypeDbType::Palette,
1✔
100
                breakpoints: Some(
1✔
101
                    colors
1✔
102
                        .0
1✔
103
                        .iter()
1✔
104
                        .map(|(k, v)| Breakpoint {
3✔
105
                            value: (*k).into(),
3✔
106
                            color: *v,
3✔
107
                        })
3✔
108
                        .collect(),
1✔
109
                ),
1✔
110
                no_data_color: Some(*no_data_color),
1✔
111
                color_fields: None,
1✔
112
                default_color: Some(*default_color),
1✔
113
            },
1✔
114
            Colorizer::Rgba => ColorizerDbType {
4✔
115
                r#type: ColorizerTypeDbType::Rgba,
4✔
116
                breakpoints: None,
4✔
117
                no_data_color: None,
4✔
118
                color_fields: None,
4✔
119
                default_color: None,
4✔
120
            },
4✔
121
        }
122
    }
18✔
123
}
124

125
impl TryFrom<ColorizerDbType> for Colorizer {
126
    type Error = Error;
127

128
    fn try_from(value: ColorizerDbType) -> Result<Self, Self::Error> {
129
        match value {
10✔
130
            ColorizerDbType {
131
                r#type: ColorizerTypeDbType::LinearGradient,
132
                breakpoints: Some(breakpoints),
10✔
133
                no_data_color: Some(no_data_color),
10✔
134
                color_fields: Some(color_fields),
10✔
135
                default_color: None,
10✔
136
            } => Ok(Self::LinearGradient(LinearGradient {
10✔
137
                breakpoints,
10✔
138
                no_data_color,
10✔
139
                color_fields: color_fields.try_into()?,
10✔
140
            })),
141
            ColorizerDbType {
142
                r#type: ColorizerTypeDbType::LogarithmicGradient,
143
                breakpoints: Some(breakpoints),
1✔
144
                no_data_color: Some(no_data_color),
1✔
145
                color_fields: Some(color_fields),
1✔
146
                default_color: None,
1✔
147
            } => Ok(Self::LogarithmicGradient(LogarithmicGradient {
1✔
148
                breakpoints,
1✔
149
                no_data_color,
1✔
150
                color_fields: color_fields.try_into()?,
1✔
151
            })),
152
            ColorizerDbType {
153
                r#type: ColorizerTypeDbType::Palette,
154
                breakpoints: Some(breakpoints),
1✔
155
                no_data_color: Some(no_data_color),
1✔
156
                color_fields: None,
1✔
157
                default_color: Some(default_color),
1✔
158
            } => Ok(Self::Palette {
1✔
159
                colors: Palette(
1✔
160
                    breakpoints
1✔
161
                        .into_iter()
1✔
162
                        .map(|b| (NotNan::<f64>::from(b.value), b.color))
3✔
163
                        .collect(),
1✔
164
                ),
1✔
165
                no_data_color,
1✔
166
                default_color,
1✔
167
            }),
1✔
168
            ColorizerDbType {
169
                r#type: ColorizerTypeDbType::Rgba,
170
                breakpoints: None,
171
                no_data_color: None,
172
                color_fields: None,
173
                default_color: None,
174
            } => Ok(Self::Rgba),
4✔
175
            _ => Err(Error::UnexpectedInvalidDbTypeConversion),
×
176
        }
177
    }
16✔
178
}
179

180
#[derive(Debug, ToSql, FromSql)]
4,352✔
181
#[postgres(name = "ColorParam")]
182
pub struct ColorParamDbType {
183
    color: Option<RgbaColor>,
184
    attribute: Option<String>,
185
    colorizer: Option<Colorizer>,
186
}
187

188
impl From<&ColorParam> for ColorParamDbType {
189
    fn from(value: &ColorParam) -> Self {
34✔
190
        match value {
34✔
191
            ColorParam::Static { color } => Self {
33✔
192
                color: Some((*color).into()),
33✔
193
                attribute: None,
33✔
194
                colorizer: None,
33✔
195
            },
33✔
196
            ColorParam::Derived(DerivedColor {
197
                attribute,
1✔
198
                colorizer,
1✔
199
            }) => Self {
1✔
200
                color: None,
1✔
201
                attribute: Some(attribute.clone()),
1✔
202
                colorizer: Some(colorizer.clone()),
1✔
203
            },
1✔
204
        }
205
    }
34✔
206
}
207

208
impl TryFrom<ColorParamDbType> for ColorParam {
209
    type Error = Error;
210

211
    fn try_from(value: ColorParamDbType) -> Result<Self, Self::Error> {
212
        match value {
1✔
213
            ColorParamDbType {
214
                color: Some(color),
27✔
215
                attribute: None,
27✔
216
                colorizer: None,
27✔
217
            } => Ok(Self::Static {
27✔
218
                color: color.into(),
27✔
219
            }),
27✔
220
            ColorParamDbType {
221
                color: None,
222
                attribute: Some(attribute),
1✔
223
                colorizer: Some(colorizer),
1✔
224
            } => Ok(Self::Derived(DerivedColor {
1✔
225
                attribute,
1✔
226
                colorizer,
1✔
227
            })),
1✔
228
            _ => Err(Error::UnexpectedInvalidDbTypeConversion),
×
229
        }
230
    }
28✔
231
}
232

233
#[derive(Debug, ToSql, FromSql)]
3,470✔
234
#[postgres(name = "NumberParam")]
235
pub struct NumberParamDbType {
236
    value: Option<i64>,
237
    attribute: Option<String>,
238
    factor: Option<f64>,
239
    default_value: Option<f64>,
240
}
241

242
impl From<&NumberParam> for NumberParamDbType {
243
    fn from(value: &NumberParam) -> Self {
29✔
244
        match value {
29✔
245
            NumberParam::Static { value } => Self {
28✔
246
                value: Some(*value as i64),
28✔
247
                attribute: None,
28✔
248
                factor: None,
28✔
249
                default_value: None,
28✔
250
            },
28✔
251
            NumberParam::Derived(DerivedNumber {
252
                attribute,
1✔
253
                factor,
1✔
254
                default_value,
1✔
255
            }) => Self {
1✔
256
                value: None,
1✔
257
                attribute: Some(attribute.clone()),
1✔
258
                factor: Some(*factor),
1✔
259
                default_value: Some(*default_value),
1✔
260
            },
1✔
261
        }
262
    }
29✔
263
}
264

265
impl TryFrom<NumberParamDbType> for NumberParam {
266
    type Error = Error;
267

268
    fn try_from(value: NumberParamDbType) -> Result<Self, Self::Error> {
269
        match value {
1✔
270
            NumberParamDbType {
271
                value: Some(value),
22✔
272
                attribute: None,
22✔
273
                factor: None,
22✔
274
                default_value: None,
22✔
275
            } => Ok(Self::Static {
22✔
276
                value: value as usize,
22✔
277
            }),
22✔
278
            NumberParamDbType {
279
                value: None,
280
                attribute: Some(attribute),
1✔
281
                factor: Some(factor),
1✔
282
                default_value: Some(default_value),
1✔
283
            } => Ok(Self::Derived(DerivedNumber {
1✔
284
                attribute,
1✔
285
                factor,
1✔
286
                default_value,
1✔
287
            })),
1✔
288
            _ => Err(Error::UnexpectedInvalidDbTypeConversion),
×
289
        }
290
    }
23✔
291
}
292

293
#[derive(Debug, ToSql, FromSql)]
490✔
294
#[postgres(name = "Symbology")]
295
pub struct SymbologyDbType {
296
    raster: Option<RasterSymbology>,
297
    point: Option<PointSymbology>,
298
    line: Option<LineSymbology>,
299
    polygon: Option<PolygonSymbology>,
300
}
301

302
impl From<&Symbology> for SymbologyDbType {
303
    fn from(symbology: &Symbology) -> Self {
25✔
304
        match symbology {
25✔
305
            Symbology::Raster(raster) => SymbologyDbType {
13✔
306
                raster: Some(raster.clone()),
13✔
307
                point: None,
13✔
308
                line: None,
13✔
309
                polygon: None,
13✔
310
            },
13✔
311
            Symbology::Point(point) => SymbologyDbType {
10✔
312
                raster: None,
10✔
313
                point: Some(point.clone()),
10✔
314
                line: None,
10✔
315
                polygon: None,
10✔
316
            },
10✔
317
            Symbology::Line(line) => SymbologyDbType {
1✔
318
                raster: None,
1✔
319
                point: None,
1✔
320
                line: Some(line.clone()),
1✔
321
                polygon: None,
1✔
322
            },
1✔
323
            Symbology::Polygon(polygon) => SymbologyDbType {
1✔
324
                raster: None,
1✔
325
                point: None,
1✔
326
                line: None,
1✔
327
                polygon: Some(polygon.clone()),
1✔
328
            },
1✔
329
        }
330
    }
25✔
331
}
332

333
impl TryFrom<SymbologyDbType> for Symbology {
334
    type Error = Error;
335

336
    fn try_from(symbology: SymbologyDbType) -> Result<Self, Self::Error> {
337
        match symbology {
2✔
338
            SymbologyDbType {
339
                raster: Some(raster),
11✔
340
                point: None,
11✔
341
                line: None,
11✔
342
                polygon: None,
11✔
343
            } => Ok(Self::Raster(raster)),
11✔
344
            SymbologyDbType {
345
                raster: None,
346
                point: Some(point),
7✔
347
                line: None,
7✔
348
                polygon: None,
7✔
349
            } => Ok(Self::Point(point)),
7✔
350
            SymbologyDbType {
351
                raster: None,
352
                point: None,
353
                line: Some(line),
1✔
354
                polygon: None,
1✔
355
            } => Ok(Self::Line(line)),
1✔
356
            SymbologyDbType {
357
                raster: None,
358
                point: None,
359
                line: None,
360
                polygon: Some(polygon),
1✔
361
            } => Ok(Self::Polygon(polygon)),
1✔
362
            _ => Err(Error::UnexpectedInvalidDbTypeConversion),
×
363
        }
364
    }
20✔
365
}
366

367
/// A macro for quickly implementing `FromSql` and `ToSql` for `$RustType` if there is a `From` and `Into`
368
/// implementation for another type `$DbType` that already implements it.
369
///
370
/// # Usage
371
///
372
/// ```rust,ignore
373
/// delegate_from_to_sql!($RustType, $DbType)
374
/// ```
375
///
376
macro_rules! delegate_from_to_sql {
377
    ( $RustType:ty, $DbType:ty ) => {
378
        impl ToSql for $RustType {
379
            fn to_sql(
108✔
380
                &self,
108✔
381
                ty: &postgres_types::Type,
108✔
382
                w: &mut bytes::BytesMut,
108✔
383
            ) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>> {
108✔
384
                <$DbType as ToSql>::to_sql(&self.into(), ty, w)
108✔
385
            }
108✔
386

387
            fn accepts(ty: &postgres_types::Type) -> bool {
78✔
388
                <$DbType as FromSql>::accepts(ty)
78✔
389
            }
78✔
390

391
            postgres_types::to_sql_checked!();
392
        }
393

394
        impl<'a> FromSql<'a> for $RustType {
395
            fn from_sql(
89✔
396
                ty: &postgres_types::Type,
89✔
397
                raw: &'a [u8],
89✔
398
            ) -> Result<$RustType, Box<dyn std::error::Error + Sync + Send>> {
89✔
399
                Ok(<$DbType as FromSql>::from_sql(ty, raw)?.try_into()?)
89✔
400
            }
89✔
401

402
            fn accepts(ty: &postgres_types::Type) -> bool {
3,000✔
403
                <$DbType as FromSql>::accepts(ty)
3,000✔
404
            }
3,000✔
405
        }
406
    };
407
}
408

409
delegate_from_to_sql!(ColorParam, ColorParamDbType);
410
delegate_from_to_sql!(Colorizer, ColorizerDbType);
411
delegate_from_to_sql!(DefaultColors, DefaultColorsDbType);
412
delegate_from_to_sql!(NumberParam, NumberParamDbType);
413
delegate_from_to_sql!(Symbology, SymbologyDbType);
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