1use crate::error::Result;
12use crate::schema::Row;
13use mongreldb_kit_core::schema::{ColumnType, Table as KitTable};
14use serde_json::{Map, Value};
15
16fn escape(s: &str) -> String {
17 let mut o = String::with_capacity(s.len());
18 for c in s.chars() {
19 match c {
20 '\\' => o.push_str("\\\\"),
21 '\t' => o.push_str("\\t"),
22 '\n' => o.push_str("\\n"),
23 '\r' => o.push_str("\\r"),
24 _ => o.push(c),
25 }
26 }
27 o
28}
29
30fn unescape(s: &str) -> String {
31 let mut o = String::with_capacity(s.len());
32 let mut it = s.chars();
33 while let Some(c) = it.next() {
34 if c == '\\' {
35 match it.next() {
36 Some('t') => o.push('\t'),
37 Some('n') => o.push('\n'),
38 Some('r') => o.push('\r'),
39 Some('\\') => o.push('\\'),
40 Some(other) => {
41 o.push('\\');
42 o.push(other);
43 }
44 None => o.push('\\'),
45 }
46 } else {
47 o.push(c);
48 }
49 }
50 o
51}
52
53fn cell_to_tsv(v: &Value) -> String {
54 match v {
55 Value::Null => String::new(),
56 Value::String(s) => escape(s),
57 Value::Bool(b) => b.to_string(),
58 Value::Number(n) => n.to_string(),
59 other => escape(&serde_json::to_string(other).unwrap_or_default()),
60 }
61}
62
63pub fn rows_to_tsv(table: &KitTable, rows: &[Row]) -> String {
65 let cols: Vec<&str> = table.columns.iter().map(|c| c.name.as_str()).collect();
66 let mut out = String::new();
67 out.push_str(&cols.join("\t"));
68 out.push('\n');
69 for row in rows {
70 let line: Vec<String> = cols
71 .iter()
72 .map(|name| cell_to_tsv(row.values.get(*name).unwrap_or(&Value::Null)))
73 .collect();
74 out.push_str(&line.join("\t"));
75 out.push('\n');
76 }
77 out
78}
79
80fn parse_cell(raw: &str, ty: ColumnType) -> Result<Value> {
81 if raw.is_empty() {
82 return Ok(Value::Null);
83 }
84 let text = unescape(raw);
85 let v = match ty {
86 ColumnType::Bool => Value::Bool(text == "true"),
87 ColumnType::Int8
88 | ColumnType::Int16
89 | ColumnType::Int32
90 | ColumnType::Int64
91 | ColumnType::TimestampNanos => match text.parse::<i64>() {
92 Ok(n) => Value::Number(n.into()),
93 Err(_) => Value::String(text),
94 },
95 ColumnType::Float32 | ColumnType::Float64 => match text.parse::<f64>() {
96 Ok(f) => serde_json::Number::from_f64(f)
97 .map(Value::Number)
98 .unwrap_or(Value::Null),
99 Err(_) => Value::String(text),
100 },
101 ColumnType::Text
102 | ColumnType::Date
103 | ColumnType::DateTime
104 | ColumnType::Date64
105 | ColumnType::Time64
106 | ColumnType::Interval
107 | ColumnType::Decimal128
108 | ColumnType::Uuid
109 | ColumnType::JsonNative
110 | ColumnType::Array => Value::String(text),
111 ColumnType::Bytes | ColumnType::Json | ColumnType::Embedding | ColumnType::Sparse => {
112 serde_json::from_str(&text).unwrap_or(Value::String(text))
113 }
114 };
115 Ok(v)
116}
117
118pub fn tsv_to_rows(table: &KitTable, text: &str) -> Result<Vec<Map<String, Value>>> {
121 let mut lines = text.split('\n');
122 let header = match lines.next() {
123 Some(h) if !h.is_empty() => h,
124 _ => return Ok(Vec::new()),
125 };
126 let names: Vec<String> = header.split('\t').map(|s| s.to_string()).collect();
127 let types: Vec<Option<ColumnType>> = names
128 .iter()
129 .map(|n| {
130 table
131 .columns
132 .iter()
133 .find(|c| &c.name == n)
134 .map(|c| c.application_type)
135 })
136 .collect();
137
138 let mut rows = Vec::new();
139 for line in lines {
140 if line.is_empty() {
141 continue;
142 }
143 let mut map = Map::new();
144 for (i, field) in line.split('\t').enumerate() {
145 let Some(name) = names.get(i) else { continue };
146 let Some(Some(ty)) = types.get(i) else {
147 continue; };
149 map.insert(name.clone(), parse_cell(field, *ty)?);
150 }
151 rows.push(map);
152 }
153 Ok(rows)
154}