Skip to main content

oca_data_entry/format/
csv.rs

1use std::io::Write;
2
3use crate::model::EntrySchema;
4
5pub struct CsvOptions {
6    pub include_metadata_row: bool,
7    pub label_lang: Option<String>,
8    pub metadata_lang: Option<String>,
9}
10
11pub fn write_csv(
12    schema: &EntrySchema,
13    mut out: impl Write,
14    opts: &CsvOptions,
15) -> std::io::Result<()> {
16    // Bundle SAID as a comment tag
17    writeln!(out, "# oca_bundle_said={}", schema.said)?;
18
19    // Header row
20    let headers: Vec<String> = schema
21        .attributes
22        .iter()
23        .map(|a| {
24            if opts.label_lang.is_some() {
25                a.label.clone().unwrap_or_else(|| a.name.clone())
26            } else {
27                a.name.clone()
28            }
29        })
30        .collect();
31
32    writeln!(out, "{}", headers.join(","))?;
33
34    // Metadata row
35    if opts.include_metadata_row {
36        let meta: Vec<String> = schema
37            .attributes
38            .iter()
39            .map(|a| {
40                let mut parts = Vec::new();
41                if a.required {
42                    parts.push("required".to_string());
43                }
44                if let Some(t) = &a.attr_type {
45                    parts.push(format!("type={}", t));
46                }
47                if let Some(f) = &a.format {
48                    parts.push(format!("format={}", f));
49                }
50                if let Some(u) = &a.unit {
51                    parts.push(format!("unit={}", u));
52                }
53                if let Some(c) = &a.cardinality {
54                    parts.push(format!("cardinality={}", c));
55                }
56                if let Some(values) = &a.entry_values {
57                    parts.push(format!("values={}", values.join("|")));
58                }
59                parts.join("; ")
60            })
61            .collect();
62        writeln!(out, "{}", meta.join(","))?;
63    }
64
65    Ok(())
66}