1use crate::export::ExportError;
6use crate::models::odps::*;
7use serde_yaml;
8
9pub struct ODPSExporter;
11
12impl ODPSExporter {
13 pub fn export(&self, product: &ODPSDataProduct) -> Result<String, ExportError> {
23 Ok(Self::export_product(product))
24 }
25
26 pub fn export_product(product: &ODPSDataProduct) -> String {
70 let mut yaml = serde_yaml::Mapping::new();
71
72 yaml.insert(
74 serde_yaml::Value::String("apiVersion".to_string()),
75 serde_yaml::Value::String(product.api_version.clone()),
76 );
77
78 yaml.insert(
79 serde_yaml::Value::String("kind".to_string()),
80 serde_yaml::Value::String(product.kind.clone()),
81 );
82
83 yaml.insert(
84 serde_yaml::Value::String("id".to_string()),
85 serde_yaml::Value::String(product.id.clone()),
86 );
87
88 let status_str = match product.status {
89 ODPSStatus::Proposed => "proposed",
90 ODPSStatus::Draft => "draft",
91 ODPSStatus::Active => "active",
92 ODPSStatus::Deprecated => "deprecated",
93 ODPSStatus::Retired => "retired",
94 };
95 yaml.insert(
96 serde_yaml::Value::String("status".to_string()),
97 serde_yaml::Value::String(status_str.to_string()),
98 );
99
100 if let Some(name) = &product.name {
102 yaml.insert(
103 serde_yaml::Value::String("name".to_string()),
104 serde_yaml::Value::String(name.clone()),
105 );
106 }
107
108 if let Some(version) = &product.version {
109 yaml.insert(
110 serde_yaml::Value::String("version".to_string()),
111 serde_yaml::Value::String(version.clone()),
112 );
113 }
114
115 if let Some(domain) = &product.domain {
116 yaml.insert(
117 serde_yaml::Value::String("domain".to_string()),
118 serde_yaml::Value::String(domain.clone()),
119 );
120 }
121
122 if let Some(tenant) = &product.tenant {
123 yaml.insert(
124 serde_yaml::Value::String("tenant".to_string()),
125 serde_yaml::Value::String(tenant.clone()),
126 );
127 }
128
129 if !product.tags.is_empty() {
130 let tags_yaml: Vec<serde_yaml::Value> = product
131 .tags
132 .iter()
133 .map(|t| serde_yaml::Value::String(t.to_string()))
134 .collect();
135 yaml.insert(
136 serde_yaml::Value::String("tags".to_string()),
137 serde_yaml::Value::Sequence(tags_yaml),
138 );
139 }
140
141 if let Some(description) = &product.description {
142 let mut desc_map = serde_yaml::Mapping::new();
143 if let Some(purpose) = &description.purpose {
144 desc_map.insert(
145 serde_yaml::Value::String("purpose".to_string()),
146 serde_yaml::Value::String(purpose.clone()),
147 );
148 }
149 if let Some(limitations) = &description.limitations {
150 desc_map.insert(
151 serde_yaml::Value::String("limitations".to_string()),
152 serde_yaml::Value::String(limitations.clone()),
153 );
154 }
155 if let Some(usage) = &description.usage {
156 desc_map.insert(
157 serde_yaml::Value::String("usage".to_string()),
158 serde_yaml::Value::String(usage.clone()),
159 );
160 }
161 if let Some(auth_defs) = &description.authoritative_definitions {
162 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
163 if !defs_yaml.is_empty() {
164 desc_map.insert(
165 serde_yaml::Value::String("authoritativeDefinitions".to_string()),
166 serde_yaml::Value::Sequence(defs_yaml),
167 );
168 }
169 }
170 if let Some(custom_props) = &description.custom_properties {
171 let props_yaml = Self::serialize_custom_properties(custom_props);
172 if !props_yaml.is_empty() {
173 desc_map.insert(
174 serde_yaml::Value::String("customProperties".to_string()),
175 serde_yaml::Value::Sequence(props_yaml),
176 );
177 }
178 }
179 if !desc_map.is_empty() {
180 yaml.insert(
181 serde_yaml::Value::String("description".to_string()),
182 serde_yaml::Value::Mapping(desc_map),
183 );
184 }
185 }
186
187 if let Some(auth_defs) = &product.authoritative_definitions {
188 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
189 if !defs_yaml.is_empty() {
190 yaml.insert(
191 serde_yaml::Value::String("authoritativeDefinitions".to_string()),
192 serde_yaml::Value::Sequence(defs_yaml),
193 );
194 }
195 }
196
197 if let Some(custom_props) = &product.custom_properties {
198 let props_yaml = Self::serialize_custom_properties(custom_props);
199 if !props_yaml.is_empty() {
200 yaml.insert(
201 serde_yaml::Value::String("customProperties".to_string()),
202 serde_yaml::Value::Sequence(props_yaml),
203 );
204 }
205 }
206
207 if let Some(input_ports) = &product.input_ports {
208 let ports_yaml: Vec<serde_yaml::Value> = input_ports
209 .iter()
210 .map(|port| {
211 let mut port_map = serde_yaml::Mapping::new();
212 port_map.insert(
213 serde_yaml::Value::String("name".to_string()),
214 serde_yaml::Value::String(port.name.clone()),
215 );
216 port_map.insert(
217 serde_yaml::Value::String("version".to_string()),
218 serde_yaml::Value::String(port.version.clone()),
219 );
220 port_map.insert(
221 serde_yaml::Value::String("contractId".to_string()),
222 serde_yaml::Value::String(port.contract_id.clone()),
223 );
224 if !port.tags.is_empty() {
225 let tags_yaml: Vec<serde_yaml::Value> = port
226 .tags
227 .iter()
228 .map(|t| serde_yaml::Value::String(t.to_string()))
229 .collect();
230 port_map.insert(
231 serde_yaml::Value::String("tags".to_string()),
232 serde_yaml::Value::Sequence(tags_yaml),
233 );
234 }
235 if let Some(custom_props) = &port.custom_properties {
236 let props_yaml = Self::serialize_custom_properties(custom_props);
237 if !props_yaml.is_empty() {
238 port_map.insert(
239 serde_yaml::Value::String("customProperties".to_string()),
240 serde_yaml::Value::Sequence(props_yaml),
241 );
242 }
243 }
244 if let Some(auth_defs) = &port.authoritative_definitions {
245 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
246 if !defs_yaml.is_empty() {
247 port_map.insert(
248 serde_yaml::Value::String("authoritativeDefinitions".to_string()),
249 serde_yaml::Value::Sequence(defs_yaml),
250 );
251 }
252 }
253 serde_yaml::Value::Mapping(port_map)
254 })
255 .collect();
256 yaml.insert(
257 serde_yaml::Value::String("inputPorts".to_string()),
258 serde_yaml::Value::Sequence(ports_yaml),
259 );
260 }
261
262 if let Some(output_ports) = &product.output_ports {
263 let ports_yaml: Vec<serde_yaml::Value> = output_ports
264 .iter()
265 .map(|port| {
266 let mut port_map = serde_yaml::Mapping::new();
267 port_map.insert(
268 serde_yaml::Value::String("name".to_string()),
269 serde_yaml::Value::String(port.name.clone()),
270 );
271 port_map.insert(
272 serde_yaml::Value::String("version".to_string()),
273 serde_yaml::Value::String(port.version.clone()),
274 );
275 if let Some(description) = &port.description {
276 port_map.insert(
277 serde_yaml::Value::String("description".to_string()),
278 serde_yaml::Value::String(description.clone()),
279 );
280 }
281 if let Some(r#type) = &port.r#type {
282 port_map.insert(
283 serde_yaml::Value::String("type".to_string()),
284 serde_yaml::Value::String(r#type.clone()),
285 );
286 }
287 if let Some(contract_id) = &port.contract_id {
288 port_map.insert(
289 serde_yaml::Value::String("contractId".to_string()),
290 serde_yaml::Value::String(contract_id.clone()),
291 );
292 }
293 if let Some(sbom) = &port.sbom {
294 let sbom_yaml: Vec<serde_yaml::Value> = sbom
295 .iter()
296 .map(|s| {
297 let mut sbom_map = serde_yaml::Mapping::new();
298 sbom_map.insert(
299 serde_yaml::Value::String("url".to_string()),
300 serde_yaml::Value::String(s.url.clone()),
301 );
302 if let Some(r#type) = &s.r#type {
303 sbom_map.insert(
304 serde_yaml::Value::String("type".to_string()),
305 serde_yaml::Value::String(r#type.clone()),
306 );
307 }
308 serde_yaml::Value::Mapping(sbom_map)
309 })
310 .collect();
311 port_map.insert(
312 serde_yaml::Value::String("sbom".to_string()),
313 serde_yaml::Value::Sequence(sbom_yaml),
314 );
315 }
316 if let Some(input_contracts) = &port.input_contracts {
317 let contracts_yaml: Vec<serde_yaml::Value> = input_contracts
318 .iter()
319 .map(|contract| {
320 let mut contract_map = serde_yaml::Mapping::new();
321 contract_map.insert(
322 serde_yaml::Value::String("id".to_string()),
323 serde_yaml::Value::String(contract.id.clone()),
324 );
325 contract_map.insert(
326 serde_yaml::Value::String("version".to_string()),
327 serde_yaml::Value::String(contract.version.clone()),
328 );
329 serde_yaml::Value::Mapping(contract_map)
330 })
331 .collect();
332 port_map.insert(
333 serde_yaml::Value::String("inputContracts".to_string()),
334 serde_yaml::Value::Sequence(contracts_yaml),
335 );
336 }
337 if !port.tags.is_empty() {
338 let tags_yaml: Vec<serde_yaml::Value> = port
339 .tags
340 .iter()
341 .map(|t| serde_yaml::Value::String(t.to_string()))
342 .collect();
343 port_map.insert(
344 serde_yaml::Value::String("tags".to_string()),
345 serde_yaml::Value::Sequence(tags_yaml),
346 );
347 }
348 if let Some(custom_props) = &port.custom_properties {
349 let props_yaml = Self::serialize_custom_properties(custom_props);
350 if !props_yaml.is_empty() {
351 port_map.insert(
352 serde_yaml::Value::String("customProperties".to_string()),
353 serde_yaml::Value::Sequence(props_yaml),
354 );
355 }
356 }
357 if let Some(auth_defs) = &port.authoritative_definitions {
358 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
359 if !defs_yaml.is_empty() {
360 port_map.insert(
361 serde_yaml::Value::String("authoritativeDefinitions".to_string()),
362 serde_yaml::Value::Sequence(defs_yaml),
363 );
364 }
365 }
366 serde_yaml::Value::Mapping(port_map)
367 })
368 .collect();
369 yaml.insert(
370 serde_yaml::Value::String("outputPorts".to_string()),
371 serde_yaml::Value::Sequence(ports_yaml),
372 );
373 }
374
375 if let Some(management_ports) = &product.management_ports {
376 let ports_yaml: Vec<serde_yaml::Value> = management_ports
377 .iter()
378 .map(|port| {
379 let mut port_map = serde_yaml::Mapping::new();
380 port_map.insert(
381 serde_yaml::Value::String("name".to_string()),
382 serde_yaml::Value::String(port.name.clone()),
383 );
384 port_map.insert(
385 serde_yaml::Value::String("content".to_string()),
386 serde_yaml::Value::String(port.content.clone()),
387 );
388 if let Some(r#type) = &port.r#type {
389 port_map.insert(
390 serde_yaml::Value::String("type".to_string()),
391 serde_yaml::Value::String(r#type.clone()),
392 );
393 }
394 if let Some(url) = &port.url {
395 port_map.insert(
396 serde_yaml::Value::String("url".to_string()),
397 serde_yaml::Value::String(url.clone()),
398 );
399 }
400 if let Some(channel) = &port.channel {
401 port_map.insert(
402 serde_yaml::Value::String("channel".to_string()),
403 serde_yaml::Value::String(channel.clone()),
404 );
405 }
406 if let Some(description) = &port.description {
407 port_map.insert(
408 serde_yaml::Value::String("description".to_string()),
409 serde_yaml::Value::String(description.clone()),
410 );
411 }
412 if !port.tags.is_empty() {
413 let tags_yaml: Vec<serde_yaml::Value> = port
414 .tags
415 .iter()
416 .map(|t| serde_yaml::Value::String(t.to_string()))
417 .collect();
418 port_map.insert(
419 serde_yaml::Value::String("tags".to_string()),
420 serde_yaml::Value::Sequence(tags_yaml),
421 );
422 }
423 if let Some(custom_props) = &port.custom_properties {
424 let props_yaml = Self::serialize_custom_properties(custom_props);
425 if !props_yaml.is_empty() {
426 port_map.insert(
427 serde_yaml::Value::String("customProperties".to_string()),
428 serde_yaml::Value::Sequence(props_yaml),
429 );
430 }
431 }
432 if let Some(auth_defs) = &port.authoritative_definitions {
433 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
434 if !defs_yaml.is_empty() {
435 port_map.insert(
436 serde_yaml::Value::String("authoritativeDefinitions".to_string()),
437 serde_yaml::Value::Sequence(defs_yaml),
438 );
439 }
440 }
441 serde_yaml::Value::Mapping(port_map)
442 })
443 .collect();
444 yaml.insert(
445 serde_yaml::Value::String("managementPorts".to_string()),
446 serde_yaml::Value::Sequence(ports_yaml),
447 );
448 }
449
450 if let Some(support) = &product.support {
451 let support_yaml: Vec<serde_yaml::Value> = support
452 .iter()
453 .map(|s| {
454 let mut support_map = serde_yaml::Mapping::new();
455 support_map.insert(
456 serde_yaml::Value::String("channel".to_string()),
457 serde_yaml::Value::String(s.channel.clone()),
458 );
459 support_map.insert(
460 serde_yaml::Value::String("url".to_string()),
461 serde_yaml::Value::String(s.url.clone()),
462 );
463 if let Some(description) = &s.description {
464 support_map.insert(
465 serde_yaml::Value::String("description".to_string()),
466 serde_yaml::Value::String(description.clone()),
467 );
468 }
469 if let Some(tool) = &s.tool {
470 support_map.insert(
471 serde_yaml::Value::String("tool".to_string()),
472 serde_yaml::Value::String(tool.clone()),
473 );
474 }
475 if let Some(scope) = &s.scope {
476 support_map.insert(
477 serde_yaml::Value::String("scope".to_string()),
478 serde_yaml::Value::String(scope.clone()),
479 );
480 }
481 if let Some(invitation_url) = &s.invitation_url {
482 support_map.insert(
483 serde_yaml::Value::String("invitationUrl".to_string()),
484 serde_yaml::Value::String(invitation_url.clone()),
485 );
486 }
487 if !s.tags.is_empty() {
488 let tags_yaml: Vec<serde_yaml::Value> = s
489 .tags
490 .iter()
491 .map(|t| serde_yaml::Value::String(t.to_string()))
492 .collect();
493 support_map.insert(
494 serde_yaml::Value::String("tags".to_string()),
495 serde_yaml::Value::Sequence(tags_yaml),
496 );
497 }
498 if let Some(custom_props) = &s.custom_properties {
499 let props_yaml = Self::serialize_custom_properties(custom_props);
500 if !props_yaml.is_empty() {
501 support_map.insert(
502 serde_yaml::Value::String("customProperties".to_string()),
503 serde_yaml::Value::Sequence(props_yaml),
504 );
505 }
506 }
507 if let Some(auth_defs) = &s.authoritative_definitions {
508 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
509 if !defs_yaml.is_empty() {
510 support_map.insert(
511 serde_yaml::Value::String("authoritativeDefinitions".to_string()),
512 serde_yaml::Value::Sequence(defs_yaml),
513 );
514 }
515 }
516 serde_yaml::Value::Mapping(support_map)
517 })
518 .collect();
519 yaml.insert(
520 serde_yaml::Value::String("support".to_string()),
521 serde_yaml::Value::Sequence(support_yaml),
522 );
523 }
524
525 if let Some(team) = &product.team {
526 let mut team_map = serde_yaml::Mapping::new();
527 if let Some(name) = &team.name {
528 team_map.insert(
529 serde_yaml::Value::String("name".to_string()),
530 serde_yaml::Value::String(name.clone()),
531 );
532 }
533 if let Some(description) = &team.description {
534 team_map.insert(
535 serde_yaml::Value::String("description".to_string()),
536 serde_yaml::Value::String(description.clone()),
537 );
538 }
539 if let Some(members) = &team.members {
540 let members_yaml: Vec<serde_yaml::Value> = members
541 .iter()
542 .map(|member| {
543 let mut member_map = serde_yaml::Mapping::new();
544 member_map.insert(
545 serde_yaml::Value::String("username".to_string()),
546 serde_yaml::Value::String(member.username.clone()),
547 );
548 if let Some(name) = &member.name {
549 member_map.insert(
550 serde_yaml::Value::String("name".to_string()),
551 serde_yaml::Value::String(name.clone()),
552 );
553 }
554 if let Some(description) = &member.description {
555 member_map.insert(
556 serde_yaml::Value::String("description".to_string()),
557 serde_yaml::Value::String(description.clone()),
558 );
559 }
560 if let Some(role) = &member.role {
561 member_map.insert(
562 serde_yaml::Value::String("role".to_string()),
563 serde_yaml::Value::String(role.clone()),
564 );
565 }
566 if let Some(date_in) = &member.date_in {
567 member_map.insert(
568 serde_yaml::Value::String("dateIn".to_string()),
569 serde_yaml::Value::String(date_in.clone()),
570 );
571 }
572 if let Some(date_out) = &member.date_out {
573 member_map.insert(
574 serde_yaml::Value::String("dateOut".to_string()),
575 serde_yaml::Value::String(date_out.clone()),
576 );
577 }
578 if let Some(replaced_by) = &member.replaced_by_username {
579 member_map.insert(
580 serde_yaml::Value::String("replacedByUsername".to_string()),
581 serde_yaml::Value::String(replaced_by.clone()),
582 );
583 }
584 if !member.tags.is_empty() {
585 let tags_yaml: Vec<serde_yaml::Value> = member
586 .tags
587 .iter()
588 .map(|t| serde_yaml::Value::String(t.to_string()))
589 .collect();
590 member_map.insert(
591 serde_yaml::Value::String("tags".to_string()),
592 serde_yaml::Value::Sequence(tags_yaml),
593 );
594 }
595 if let Some(custom_props) = &member.custom_properties {
596 let props_yaml = Self::serialize_custom_properties(custom_props);
597 if !props_yaml.is_empty() {
598 member_map.insert(
599 serde_yaml::Value::String("customProperties".to_string()),
600 serde_yaml::Value::Sequence(props_yaml),
601 );
602 }
603 }
604 if let Some(auth_defs) = &member.authoritative_definitions {
605 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
606 if !defs_yaml.is_empty() {
607 member_map.insert(
608 serde_yaml::Value::String(
609 "authoritativeDefinitions".to_string(),
610 ),
611 serde_yaml::Value::Sequence(defs_yaml),
612 );
613 }
614 }
615 serde_yaml::Value::Mapping(member_map)
616 })
617 .collect();
618 team_map.insert(
619 serde_yaml::Value::String("members".to_string()),
620 serde_yaml::Value::Sequence(members_yaml),
621 );
622 }
623 if !team.tags.is_empty() {
624 let tags_yaml: Vec<serde_yaml::Value> = team
625 .tags
626 .iter()
627 .map(|t| serde_yaml::Value::String(t.to_string()))
628 .collect();
629 team_map.insert(
630 serde_yaml::Value::String("tags".to_string()),
631 serde_yaml::Value::Sequence(tags_yaml),
632 );
633 }
634 if let Some(custom_props) = &team.custom_properties {
635 let props_yaml = Self::serialize_custom_properties(custom_props);
636 if !props_yaml.is_empty() {
637 team_map.insert(
638 serde_yaml::Value::String("customProperties".to_string()),
639 serde_yaml::Value::Sequence(props_yaml),
640 );
641 }
642 }
643 if let Some(auth_defs) = &team.authoritative_definitions {
644 let defs_yaml = Self::serialize_authoritative_definitions(auth_defs);
645 if !defs_yaml.is_empty() {
646 team_map.insert(
647 serde_yaml::Value::String("authoritativeDefinitions".to_string()),
648 serde_yaml::Value::Sequence(defs_yaml),
649 );
650 }
651 }
652 if !team_map.is_empty() {
653 yaml.insert(
654 serde_yaml::Value::String("team".to_string()),
655 serde_yaml::Value::Mapping(team_map),
656 );
657 }
658 }
659
660 if let Some(product_created_ts) = &product.product_created_ts {
661 yaml.insert(
662 serde_yaml::Value::String("productCreatedTs".to_string()),
663 serde_yaml::Value::String(product_created_ts.clone()),
664 );
665 }
666
667 serde_yaml::to_string(&serde_yaml::Value::Mapping(yaml))
669 .unwrap_or_else(|_| String::from(""))
670 }
671
672 fn serialize_authoritative_definitions(
674 defs: &[ODPSAuthoritativeDefinition],
675 ) -> Vec<serde_yaml::Value> {
676 defs.iter()
677 .map(|def| {
678 let mut def_map = serde_yaml::Mapping::new();
679 def_map.insert(
680 serde_yaml::Value::String("type".to_string()),
681 serde_yaml::Value::String(def.r#type.clone()),
682 );
683 def_map.insert(
684 serde_yaml::Value::String("url".to_string()),
685 serde_yaml::Value::String(def.url.clone()),
686 );
687 if let Some(description) = &def.description {
688 def_map.insert(
689 serde_yaml::Value::String("description".to_string()),
690 serde_yaml::Value::String(description.clone()),
691 );
692 }
693 serde_yaml::Value::Mapping(def_map)
694 })
695 .collect()
696 }
697
698 fn serialize_custom_properties(props: &[ODPSCustomProperty]) -> Vec<serde_yaml::Value> {
700 props
701 .iter()
702 .map(|prop| {
703 let mut prop_map = serde_yaml::Mapping::new();
704 prop_map.insert(
705 serde_yaml::Value::String("property".to_string()),
706 serde_yaml::Value::String(prop.property.clone()),
707 );
708 prop_map.insert(
709 serde_yaml::Value::String("value".to_string()),
710 Self::json_to_yaml_value(&prop.value),
711 );
712 if let Some(description) = &prop.description {
713 prop_map.insert(
714 serde_yaml::Value::String("description".to_string()),
715 serde_yaml::Value::String(description.clone()),
716 );
717 }
718 serde_yaml::Value::Mapping(prop_map)
719 })
720 .collect()
721 }
722
723 fn json_to_yaml_value(json: &serde_json::Value) -> serde_yaml::Value {
725 match json {
726 serde_json::Value::Null => serde_yaml::Value::Null,
727 serde_json::Value::Bool(b) => serde_yaml::Value::Bool(*b),
728 serde_json::Value::Number(n) => {
729 if let Some(i) = n.as_i64() {
730 serde_yaml::Value::Number(serde_yaml::Number::from(i))
731 } else if let Some(f) = n.as_f64() {
732 serde_yaml::Value::Number(serde_yaml::Number::from(f))
733 } else {
734 serde_yaml::Value::String(n.to_string())
735 }
736 }
737 serde_json::Value::String(s) => serde_yaml::Value::String(s.clone()),
738 serde_json::Value::Array(arr) => {
739 let yaml_arr: Vec<serde_yaml::Value> =
740 arr.iter().map(Self::json_to_yaml_value).collect();
741 serde_yaml::Value::Sequence(yaml_arr)
742 }
743 serde_json::Value::Object(obj) => {
744 let mut yaml_map = serde_yaml::Mapping::new();
745 for (k, v) in obj {
746 yaml_map.insert(
747 serde_yaml::Value::String(k.clone()),
748 Self::json_to_yaml_value(v),
749 );
750 }
751 serde_yaml::Value::Mapping(yaml_map)
752 }
753 }
754 }
755}