use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use super::tag::Tag;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ODPSApiVersion {
#[serde(rename = "v0.9.0")]
V0_9_0,
#[serde(rename = "v1.0.0")]
V1_0_0,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ODPSStatus {
#[serde(rename = "proposed")]
Proposed,
#[serde(rename = "draft")]
Draft,
#[serde(rename = "active")]
Active,
#[serde(rename = "deprecated")]
Deprecated,
#[serde(rename = "retired")]
Retired,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ODPSAuthoritativeDefinition {
pub r#type: String,
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ODPSCustomProperty {
pub property: String,
pub value: serde_json::Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ODPSDescription {
#[serde(skip_serializing_if = "Option::is_none")]
pub purpose: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limitations: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub usage: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_properties: Option<Vec<ODPSCustomProperty>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ODPSInputPort {
pub name: String,
pub version: String,
pub contract_id: String,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_tags"
)]
pub tags: Vec<Tag>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_properties: Option<Vec<ODPSCustomProperty>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ODPSSBOM {
#[serde(skip_serializing_if = "Option::is_none")]
pub r#type: Option<String>,
pub url: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ODPSInputContract {
pub id: String,
pub version: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ODPSOutputPort {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#type: Option<String>,
pub version: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub contract_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sbom: Option<Vec<ODPSSBOM>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub input_contracts: Option<Vec<ODPSInputContract>>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_tags"
)]
pub tags: Vec<Tag>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_properties: Option<Vec<ODPSCustomProperty>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ODPSManagementPort {
pub name: String,
pub content: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub channel: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_tags"
)]
pub tags: Vec<Tag>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_properties: Option<Vec<ODPSCustomProperty>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ODPSSupport {
pub channel: String,
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub scope: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub invitation_url: Option<String>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_tags"
)]
pub tags: Vec<Tag>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_properties: Option<Vec<ODPSCustomProperty>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ODPSTeamMember {
pub username: 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 role: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub date_in: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub date_out: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub replaced_by_username: Option<String>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_tags"
)]
pub tags: Vec<Tag>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_properties: Option<Vec<ODPSCustomProperty>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ODPSTeam {
#[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 members: Option<Vec<ODPSTeamMember>>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_tags"
)]
pub tags: Vec<Tag>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_properties: Option<Vec<ODPSCustomProperty>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ODPSDataProduct {
pub api_version: String,
pub kind: String,
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
pub status: ODPSStatus,
#[serde(skip_serializing_if = "Option::is_none")]
pub domain: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tenant: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<ODPSDescription>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_properties: Option<Vec<ODPSCustomProperty>>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_tags"
)]
pub tags: Vec<Tag>,
#[serde(skip_serializing_if = "Option::is_none")]
pub input_ports: Option<Vec<ODPSInputPort>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub output_ports: Option<Vec<ODPSOutputPort>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub management_ports: Option<Vec<ODPSManagementPort>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub support: Option<Vec<ODPSSupport>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub team: Option<ODPSTeam>,
#[serde(skip_serializing_if = "Option::is_none")]
pub product_created_ts: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated_at: Option<DateTime<Utc>>,
}
fn deserialize_tags<'de, D>(deserializer: D) -> Result<Vec<Tag>, D::Error>
where
D: serde::Deserializer<'de>,
{
struct TagVisitor;
impl<'de> serde::de::Visitor<'de> for TagVisitor {
type Value = Vec<Tag>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a vector of tags (strings or Tag objects)")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut tags = Vec::new();
while let Some(item) = seq.next_element::<serde_json::Value>()? {
match item {
serde_json::Value::String(s) => {
if let Ok(tag) = Tag::from_str(&s) {
tags.push(tag);
}
}
_ => {
if let serde_json::Value::String(s) = item
&& let Ok(tag) = Tag::from_str(&s)
{
tags.push(tag);
}
}
}
}
Ok(tags)
}
}
deserializer.deserialize_seq(TagVisitor)
}