simplify serde optional handling (#998)

This commit is contained in:
Yuri Astrakhan 2023-11-12 22:22:04 -05:00 committed by GitHub
parent 490be6b968
commit fad89d742f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 155 additions and 53 deletions

139
Cargo.lock generated
View File

@ -255,6 +255,21 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "anes"
version = "0.1.6"
@ -539,6 +554,19 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
dependencies = [
"android-tzdata",
"iana-time-zone",
"num-traits",
"serde",
"windows-targets 0.48.5",
]
[[package]]
name = "ciborium"
version = "0.2.1"
@ -828,6 +856,41 @@ dependencies = [
"syn 2.0.39",
]
[[package]]
name = "darling"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 2.0.39",
]
[[package]]
name = "darling_macro"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [
"darling_core",
"quote",
"syn 2.0.39",
]
[[package]]
name = "data-url"
version = "0.2.0"
@ -885,6 +948,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3"
dependencies = [
"powerfmt",
"serde",
]
[[package]]
@ -1474,6 +1538,35 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "iana-time-zone"
version = "0.1.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.4.0"
@ -1513,6 +1606,7 @@ dependencies = [
"autocfg",
"hashbrown 0.12.3",
"rayon",
"serde",
]
[[package]]
@ -1523,6 +1617,7 @@ checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
dependencies = [
"equivalent",
"hashbrown 0.14.2",
"serde",
]
[[package]]
@ -1757,6 +1852,7 @@ dependencies = [
"semver",
"serde",
"serde_json",
"serde_with",
"serde_yaml",
"spreet",
"subst",
@ -1788,6 +1884,7 @@ dependencies = [
"rstest",
"serde",
"serde_json",
"serde_with",
"serde_yaml",
"sqlite-hashes",
"sqlx",
@ -2903,6 +3000,35 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_with"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23"
dependencies = [
"base64",
"chrono",
"hex",
"indexmap 1.9.3",
"indexmap 2.1.0",
"serde",
"serde_json",
"serde_with_macros",
"time",
]
[[package]]
name = "serde_with_macros"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]]
name = "serde_yaml"
version = "0.9.27"
@ -2949,9 +3075,9 @@ dependencies = [
[[package]]
name = "signature"
version = "2.1.0"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
dependencies = [
"digest",
"rand_core",
@ -4020,6 +4146,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.51.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.45.0"

View File

@ -50,6 +50,7 @@ rustls-pemfile = "1"
semver = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_with = "3"
serde_yaml = "0.9"
spreet = { version = "0.9", default-features = false }
sqlite-hashes = { version = "0.5", default-features = false, features = ["md5", "window", "hex"] }

View File

@ -82,6 +82,7 @@ rustls.workspace = true
semver.workspace = true
serde.workspace = true
serde_json = { workspace = true, features = ["preserve_order"] }
serde_with.workspace = true
serde_yaml.workspace = true
spreet.workspace = true
subst.workspace = true

View File

@ -33,7 +33,7 @@ pub struct Config {
#[serde(flatten)]
pub srv: SrvConfig,
#[serde(default, skip_serializing_if = "OptOneMany::is_none")]
#[serde(default)]
pub postgres: OptOneMany<PgConfig>,
#[serde(default, skip_serializing_if = "FileConfigEnum::is_none")]
@ -45,7 +45,7 @@ pub struct Config {
#[serde(default, skip_serializing_if = "FileConfigEnum::is_none")]
pub sprites: FileConfigEnum,
#[serde(default, skip_serializing_if = "OptOneMany::is_none")]
#[serde(default)]
pub fonts: OptOneMany<PathBuf>,
#[serde(flatten)]

View File

@ -111,13 +111,13 @@ impl FileConfigEnum {
}
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct FileConfig {
/// A list of file paths
#[serde(default, skip_serializing_if = "OptOneMany::is_none")]
pub paths: OptOneMany<PathBuf>,
/// A map of source IDs to file paths or config objects
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(serialize_with = "sorted_opt_map")]
pub sources: Option<HashMap<String, FileConfigSrc>>,
#[serde(flatten)]

View File

@ -107,10 +107,10 @@ pub struct FontSources {
pub type FontCatalog = BTreeMap<String, CatalogFontEntry>;
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct CatalogFontEntry {
pub family: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub style: Option<String>,
pub glyphs: usize,
pub start: usize,

View File

@ -20,41 +20,34 @@ pub trait PgInfo {
fn to_tilejson(&self, source_id: String) -> TileJSON;
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct PgSslCerts {
/// Same as PGSSLCERT
/// ([docs](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-SSLCERT))
#[serde(skip_serializing_if = "Option::is_none")]
pub ssl_cert: Option<std::path::PathBuf>,
/// Same as PGSSLKEY
/// ([docs](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-SSLKEY))
#[serde(skip_serializing_if = "Option::is_none")]
pub ssl_key: Option<std::path::PathBuf>,
/// Same as PGSSLROOTCERT
/// ([docs](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-SSLROOTCERT))
#[serde(skip_serializing_if = "Option::is_none")]
pub ssl_root_cert: Option<std::path::PathBuf>,
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct PgConfig {
pub connection_string: Option<String>,
#[serde(flatten)]
pub ssl_certificates: PgSslCerts,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_srid: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub auto_bounds: Option<BoundsCalcType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_feature_count: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pool_size: Option<usize>,
#[serde(default, skip_serializing_if = "OptBoolObj::is_none")]
pub auto_publish: OptBoolObj<PgCfgPublish>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(serialize_with = "sorted_opt_map")]
pub tables: Option<TableInfoSources>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(serialize_with = "sorted_opt_map")]
pub functions: Option<FuncInfoSources>,
}
@ -70,12 +63,12 @@ pub struct PgCfgPublish {
pub functions: OptBoolObj<PgCfgPublishFuncs>,
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct PgCfgPublishTables {
#[serde(default, skip_serializing_if = "OptOneMany::is_none")]
#[serde(alias = "from_schema")]
pub from_schemas: OptOneMany<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(alias = "id_format")]
pub source_id_format: Option<String>,
/// A table column to use as the feature ID
@ -84,20 +77,17 @@ pub struct PgCfgPublishTables {
#[serde(default, skip_serializing_if = "OptOneMany::is_none")]
#[serde(alias = "id_column")]
pub id_columns: OptOneMany<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub clip_geom: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub buffer: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub extent: Option<u32>,
}
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct PgCfgPublishFuncs {
#[serde(default, skip_serializing_if = "OptOneMany::is_none")]
#[serde(alias = "from_schema")]
pub from_schemas: OptOneMany<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(alias = "id_format")]
pub source_id_format: Option<String>,
}

View File

@ -7,6 +7,7 @@ use crate::pg::utils::{patch_json, InfoMap};
pub type FuncInfoSources = InfoMap<FunctionInfo>;
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)]
pub struct FunctionInfo {
/// Schema name
@ -16,18 +17,15 @@ pub struct FunctionInfo {
pub function: String,
/// An integer specifying the minimum zoom level
#[serde(skip_serializing_if = "Option::is_none")]
pub minzoom: Option<u8>,
/// An integer specifying the maximum zoom level. MUST be >= minzoom
#[serde(skip_serializing_if = "Option::is_none")]
pub maxzoom: Option<u8>,
/// The maximum extent of available map tiles. Bounds MUST define an area
/// covered by all zoom levels. The bounds are represented in WGS:84
/// latitude and longitude values, in the order left, bottom, right, top.
/// Values may be integers or floating point numbers.
#[serde(skip_serializing_if = "Option::is_none")]
pub bounds: Option<Bounds>,
/// TileJSON provided by the SQL function comment. Not serialized.

View File

@ -10,10 +10,10 @@ use crate::utils::sorted_opt_map;
pub type TableInfoSources = InfoMap<TableInfo>;
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)]
pub struct TableInfo {
/// ID of the layer as specified in a tile (ST_AsMVT param)
#[serde(skip_serializing_if = "Option::is_none")]
pub layer_id: Option<String>,
/// Table schema
@ -37,38 +37,30 @@ pub struct TableInfo {
pub is_view: Option<bool>,
/// Feature id column name
#[serde(skip_serializing_if = "Option::is_none")]
pub id_column: Option<String>,
/// An integer specifying the minimum zoom level
#[serde(skip_serializing_if = "Option::is_none")]
pub minzoom: Option<u8>,
/// An integer specifying the maximum zoom level. MUST be >= minzoom
#[serde(skip_serializing_if = "Option::is_none")]
pub maxzoom: Option<u8>,
/// The maximum extent of available map tiles. Bounds MUST define an area
/// covered by all zoom levels. The bounds are represented in WGS:84
/// latitude and longitude values, in the order left, bottom, right, top.
/// Values may be integers or floating point numbers.
#[serde(skip_serializing_if = "Option::is_none")]
pub bounds: Option<Bounds>,
/// Tile extent in tile coordinate space
#[serde(skip_serializing_if = "Option::is_none")]
pub extent: Option<u32>,
/// Buffer distance in tile coordinate space to optionally clip geometries
#[serde(skip_serializing_if = "Option::is_none")]
pub buffer: Option<u32>,
/// Boolean to control if geometries should be clipped or encoded as is
#[serde(skip_serializing_if = "Option::is_none")]
pub clip_geom: Option<bool>,
/// Geometry type
#[serde(skip_serializing_if = "Option::is_none")]
pub geometry_type: Option<String>,
/// List of columns, that should be encoded as tile properties

View File

@ -27,32 +27,21 @@ pub type SqlFuncInfoMapMap = InfoMap<InfoMap<(PgSqlInfo, FunctionInfo)>>;
pub type SqlTableInfoMapMapMap = InfoMap<InfoMap<InfoMap<TableInfo>>>;
#[derive(Debug, PartialEq)]
#[cfg_attr(test, derive(serde::Serialize))]
#[cfg_attr(test, serde_with::skip_serializing_none, derive(serde::Serialize))]
pub struct PgBuilderFuncs {
#[cfg_attr(test, serde(skip_serializing_if = "Option::is_none"))]
schemas: Option<HashSet<String>>,
source_id_format: String,
}
#[derive(Debug, Default, PartialEq)]
#[cfg_attr(test, derive(serde::Serialize))]
#[cfg_attr(test, serde_with::skip_serializing_none, derive(serde::Serialize))]
pub struct PgBuilderTables {
#[cfg_attr(
test,
serde(
skip_serializing_if = "Option::is_none",
serialize_with = "crate::utils::sorted_opt_set"
)
)]
#[cfg_attr(test, serde(serialize_with = "crate::utils::sorted_opt_set"))]
schemas: Option<HashSet<String>>,
source_id_format: String,
#[cfg_attr(test, serde(skip_serializing_if = "Option::is_none"))]
id_columns: Option<Vec<String>>,
#[cfg_attr(test, serde(skip_serializing_if = "Option::is_none"))]
clip_geom: Option<bool>,
#[cfg_attr(test, serde(skip_serializing_if = "Option::is_none"))]
buffer: Option<u32>,
#[cfg_attr(test, serde(skip_serializing_if = "Option::is_none"))]
extent: Option<u32>,
}

View File

@ -135,16 +135,13 @@ impl Clone for Box<dyn Source> {
}
}
#[serde_with::skip_serializing_none]
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct CatalogSourceEntry {
pub content_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub content_encoding: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attribution: Option<String>,
}

View File

@ -3,13 +3,11 @@ use serde::{Deserialize, Serialize};
pub const KEEP_ALIVE_DEFAULT: u64 = 75;
pub const LISTEN_ADDRESSES_DEFAULT: &str = "0.0.0.0:3000";
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)]
pub struct SrvConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub keep_alive: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub listen_addresses: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub worker_processes: Option<usize>,
}

View File

@ -21,6 +21,7 @@ log.workspace = true
martin-tile-utils.workspace = true
serde.workspace = true
serde_json.workspace = true
serde_with.workspace = true
sqlite-hashes.workspace = true
sqlx.workspace = true
thiserror.workspace = true