use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
fn default_sample_records() -> usize {
100
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct CatalogSpec {
pub url: String,
#[serde(default = "default_sample_records")]
pub sample_records: usize,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub datasets: Vec<DatasetAnnotationSpec>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct DatasetAnnotationSpec {
pub dataset: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub owners: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub consumers: Vec<ConsumerSpec>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct ConsumerSpec {
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub kind: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub contact: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub columns: Vec<String>,
}
impl DatasetAnnotationSpec {
pub fn matches(&self, id: &str, uri: &str) -> bool {
self.dataset == id || self.dataset == uri
}
pub fn to_annotation(
&self,
now: chrono::DateTime<chrono::Utc>,
) -> crate::serve::history::catalog::CatalogAnnotation {
crate::serve::history::catalog::CatalogAnnotation {
owners: (!self.owners.is_empty()).then(|| self.owners.clone()),
consumers: self
.consumers
.iter()
.map(|c| crate::serve::history::catalog::CatalogConsumer {
name: c.name.clone(),
kind: c.kind.clone(),
contact: c.contact.clone(),
columns: c.columns.clone(),
registered_by: "config".to_string(),
registered_at: now,
})
.collect(),
replace_consumers: false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_minimal_block_with_defaults() {
let spec: CatalogSpec = serde_yaml::from_str("url: sqlite:./cat.db").unwrap();
assert_eq!(spec.url, "sqlite:./cat.db");
assert_eq!(spec.sample_records, 100);
assert!(spec.datasets.is_empty());
}
#[test]
fn rejects_unknown_fields() {
let err = serde_yaml::from_str::<CatalogSpec>("url: memory\nnope: 1").unwrap_err();
assert!(err.to_string().contains("nope"));
}
#[test]
fn schema_generates() {
let schema = schemars::schema_for!(CatalogSpec);
let v = serde_json::to_value(&schema).unwrap();
assert!(v["properties"]["url"].is_object());
}
}