use crate::document::Column;
use crate::error::{Error, Result};
use crate::value::{parse_literal, Value};
pub(crate) fn parse_stream(
table_name: &str,
delimiter: char,
columns: &[Column],
body: &str,
) -> Result<Vec<Vec<Value>>> {
if columns.is_empty() {
if body.trim().is_empty() {
return Ok(Vec::new());
}
return Err(Error::RowWidthMismatch {
table: table_name.to_string(),
got: 1,
expected: 0,
});
}
let mut fields: Vec<Value> = Vec::new();
let mut col_idx = 0usize;
let mut buf = String::new();
let mut in_quotes = false;
let mut field_started = false;
let mut quote_closed = false;
let mut chars = body.chars().peekable();
while let Some(c) = chars.next() {
if in_quotes {
if c == '"' {
if chars.peek() == Some(&'"') {
chars.next();
buf.push('"');
} else {
in_quotes = false;
quote_closed = true;
}
} else {
buf.push(c);
}
continue;
}
if c == '"' {
in_quotes = true;
field_started = true;
continue;
}
if c == delimiter {
let column = &columns[col_idx];
let literal = buf.trim();
let value = if !field_started && literal.is_empty() {
Value::Null
} else if column.ty.is_quoted() {
Value::Str(buf.clone())
} else {
parse_literal(column.ty, literal, &column.name)?
};
fields.push(value);
buf.clear();
field_started = false;
quote_closed = false;
col_idx = (col_idx + 1) % columns.len();
continue;
}
if c.is_whitespace() {
if field_started && !quote_closed {
buf.push(c);
}
continue;
}
if quote_closed {
continue;
}
field_started = true;
buf.push(c);
}
if in_quotes {
return Err(Error::UnterminatedString(table_name.to_string()));
}
if field_started || !buf.is_empty() {
let column = &columns[col_idx];
let literal = buf.trim();
let value = if column.ty.is_quoted() {
Value::Str(buf.clone())
} else {
parse_literal(column.ty, literal, &column.name)?
};
fields.push(value);
}
if fields.len() % columns.len() != 0 {
return Err(Error::RowWidthMismatch {
table: table_name.to_string(),
got: fields.len() % columns.len(),
expected: columns.len(),
});
}
let mut rows = Vec::with_capacity(fields.len() / columns.len());
let mut iter = fields.into_iter();
loop {
let row: Vec<Value> = (&mut iter).take(columns.len()).collect();
if row.is_empty() {
break;
}
rows.push(row);
}
Ok(rows)
}