1use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use std::str::FromStr;
8
9use super::tag::Tag;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "lowercase")]
14pub enum ODPSApiVersion {
15 #[serde(rename = "v0.9.0")]
16 V0_9_0,
17 #[serde(rename = "v1.0.0")]
18 V1_0_0,
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
23pub enum ODPSStatus {
24 #[serde(rename = "proposed")]
25 Proposed,
26 #[serde(rename = "draft")]
27 Draft,
28 #[serde(rename = "active")]
29 Active,
30 #[serde(rename = "deprecated")]
31 Deprecated,
32 #[serde(rename = "retired")]
33 Retired,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
38pub struct ODPSAuthoritativeDefinition {
39 pub r#type: String,
41 pub url: String,
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub description: Option<String>,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
50pub struct ODPSCustomProperty {
51 pub property: String,
53 pub value: serde_json::Value,
55 #[serde(skip_serializing_if = "Option::is_none")]
57 pub description: Option<String>,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
62pub struct ODPSDescription {
63 #[serde(skip_serializing_if = "Option::is_none")]
65 pub purpose: Option<String>,
66 #[serde(skip_serializing_if = "Option::is_none")]
68 pub limitations: Option<String>,
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub usage: Option<String>,
72 #[serde(skip_serializing_if = "Option::is_none")]
74 pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
75 #[serde(skip_serializing_if = "Option::is_none")]
77 pub custom_properties: Option<Vec<ODPSCustomProperty>>,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
82pub struct ODPSInputPort {
83 pub name: String,
85 pub version: String,
87 pub contract_id: String,
89 #[serde(default, deserialize_with = "deserialize_tags")]
91 pub tags: Vec<Tag>,
92 #[serde(skip_serializing_if = "Option::is_none")]
94 pub custom_properties: Option<Vec<ODPSCustomProperty>>,
95 #[serde(skip_serializing_if = "Option::is_none")]
97 pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
102pub struct ODPSSBOM {
103 #[serde(skip_serializing_if = "Option::is_none")]
105 pub r#type: Option<String>,
106 pub url: String,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
112pub struct ODPSInputContract {
113 pub id: String,
115 pub version: String,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
121pub struct ODPSOutputPort {
122 pub name: String,
124 #[serde(skip_serializing_if = "Option::is_none")]
126 pub description: Option<String>,
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub r#type: Option<String>,
130 pub version: String,
132 #[serde(skip_serializing_if = "Option::is_none")]
134 pub contract_id: Option<String>,
135 #[serde(skip_serializing_if = "Option::is_none")]
137 pub sbom: Option<Vec<ODPSSBOM>>,
138 #[serde(skip_serializing_if = "Option::is_none")]
140 pub input_contracts: Option<Vec<ODPSInputContract>>,
141 #[serde(default, deserialize_with = "deserialize_tags")]
143 pub tags: Vec<Tag>,
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub custom_properties: Option<Vec<ODPSCustomProperty>>,
147 #[serde(skip_serializing_if = "Option::is_none")]
149 pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
154pub struct ODPSManagementPort {
155 pub name: String,
157 pub content: String,
159 #[serde(skip_serializing_if = "Option::is_none")]
161 pub r#type: Option<String>,
162 #[serde(skip_serializing_if = "Option::is_none")]
164 pub url: Option<String>,
165 #[serde(skip_serializing_if = "Option::is_none")]
167 pub channel: Option<String>,
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub description: Option<String>,
171 #[serde(default, deserialize_with = "deserialize_tags")]
173 pub tags: Vec<Tag>,
174 #[serde(skip_serializing_if = "Option::is_none")]
176 pub custom_properties: Option<Vec<ODPSCustomProperty>>,
177 #[serde(skip_serializing_if = "Option::is_none")]
179 pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
184pub struct ODPSSupport {
185 pub channel: String,
187 pub url: String,
189 #[serde(skip_serializing_if = "Option::is_none")]
191 pub description: Option<String>,
192 #[serde(skip_serializing_if = "Option::is_none")]
194 pub tool: Option<String>,
195 #[serde(skip_serializing_if = "Option::is_none")]
197 pub scope: Option<String>,
198 #[serde(skip_serializing_if = "Option::is_none")]
200 pub invitation_url: Option<String>,
201 #[serde(default, deserialize_with = "deserialize_tags")]
203 pub tags: Vec<Tag>,
204 #[serde(skip_serializing_if = "Option::is_none")]
206 pub custom_properties: Option<Vec<ODPSCustomProperty>>,
207 #[serde(skip_serializing_if = "Option::is_none")]
209 pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
210}
211
212#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
214pub struct ODPSTeamMember {
215 pub username: String,
217 #[serde(skip_serializing_if = "Option::is_none")]
219 pub name: Option<String>,
220 #[serde(skip_serializing_if = "Option::is_none")]
222 pub description: Option<String>,
223 #[serde(skip_serializing_if = "Option::is_none")]
225 pub role: Option<String>,
226 #[serde(skip_serializing_if = "Option::is_none")]
228 pub date_in: Option<String>,
229 #[serde(skip_serializing_if = "Option::is_none")]
231 pub date_out: Option<String>,
232 #[serde(skip_serializing_if = "Option::is_none")]
234 pub replaced_by_username: Option<String>,
235 #[serde(default, deserialize_with = "deserialize_tags")]
237 pub tags: Vec<Tag>,
238 #[serde(skip_serializing_if = "Option::is_none")]
240 pub custom_properties: Option<Vec<ODPSCustomProperty>>,
241 #[serde(skip_serializing_if = "Option::is_none")]
243 pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
244}
245
246#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
248pub struct ODPSTeam {
249 #[serde(skip_serializing_if = "Option::is_none")]
251 pub name: Option<String>,
252 #[serde(skip_serializing_if = "Option::is_none")]
254 pub description: Option<String>,
255 #[serde(skip_serializing_if = "Option::is_none")]
257 pub members: Option<Vec<ODPSTeamMember>>,
258 #[serde(default, deserialize_with = "deserialize_tags")]
260 pub tags: Vec<Tag>,
261 #[serde(skip_serializing_if = "Option::is_none")]
263 pub custom_properties: Option<Vec<ODPSCustomProperty>>,
264 #[serde(skip_serializing_if = "Option::is_none")]
266 pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
267}
268
269#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
271pub struct ODPSDataProduct {
272 #[serde(rename = "apiVersion")]
274 pub api_version: String,
275 pub kind: String,
277 pub id: String,
279 #[serde(skip_serializing_if = "Option::is_none")]
281 pub name: Option<String>,
282 #[serde(skip_serializing_if = "Option::is_none")]
284 pub version: Option<String>,
285 pub status: ODPSStatus,
287 #[serde(skip_serializing_if = "Option::is_none")]
289 pub domain: Option<String>,
290 #[serde(skip_serializing_if = "Option::is_none")]
292 pub tenant: Option<String>,
293 #[serde(skip_serializing_if = "Option::is_none")]
295 pub authoritative_definitions: Option<Vec<ODPSAuthoritativeDefinition>>,
296 #[serde(skip_serializing_if = "Option::is_none")]
298 pub description: Option<ODPSDescription>,
299 #[serde(skip_serializing_if = "Option::is_none")]
301 pub custom_properties: Option<Vec<ODPSCustomProperty>>,
302 #[serde(default, deserialize_with = "deserialize_tags")]
304 pub tags: Vec<Tag>,
305 #[serde(skip_serializing_if = "Option::is_none")]
307 pub input_ports: Option<Vec<ODPSInputPort>>,
308 #[serde(skip_serializing_if = "Option::is_none")]
310 pub output_ports: Option<Vec<ODPSOutputPort>>,
311 #[serde(skip_serializing_if = "Option::is_none")]
313 pub management_ports: Option<Vec<ODPSManagementPort>>,
314 #[serde(skip_serializing_if = "Option::is_none")]
316 pub support: Option<Vec<ODPSSupport>>,
317 #[serde(skip_serializing_if = "Option::is_none")]
319 pub team: Option<ODPSTeam>,
320 #[serde(skip_serializing_if = "Option::is_none")]
322 pub product_created_ts: Option<String>,
323 #[serde(skip_serializing_if = "Option::is_none")]
325 pub created_at: Option<DateTime<Utc>>,
326 #[serde(skip_serializing_if = "Option::is_none")]
328 pub updated_at: Option<DateTime<Utc>>,
329}
330
331fn deserialize_tags<'de, D>(deserializer: D) -> Result<Vec<Tag>, D::Error>
333where
334 D: serde::Deserializer<'de>,
335{
336 struct TagVisitor;
338
339 impl<'de> serde::de::Visitor<'de> for TagVisitor {
340 type Value = Vec<Tag>;
341
342 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
343 formatter.write_str("a vector of tags (strings or Tag objects)")
344 }
345
346 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
347 where
348 A: serde::de::SeqAccess<'de>,
349 {
350 let mut tags = Vec::new();
351 while let Some(item) = seq.next_element::<serde_json::Value>()? {
352 match item {
353 serde_json::Value::String(s) => {
354 if let Ok(tag) = Tag::from_str(&s) {
356 tags.push(tag);
357 }
358 }
359 _ => {
360 if let serde_json::Value::String(s) = item
362 && let Ok(tag) = Tag::from_str(&s)
363 {
364 tags.push(tag);
365 }
366 }
367 }
368 }
369 Ok(tags)
370 }
371 }
372
373 deserializer.deserialize_seq(TagVisitor)
374}