use crate::row_format::*;
use crate::Timestamp;
use byteorder::ByteOrder;
use escape_string::split_one;
pub fn add_from_stream<R: std::io::BufRead>(
tx: &mut crate::CreateTx,
format: &str,
input: &mut R,
timestamp_format: Option<&str>,
) -> Result<(), crate::WriteFailure> {
let row_format = parse_row_format(format);
let mut line = String::new();
let mut row_data = vec![];
while 0 != input.read_line(&mut line).unwrap() {
let tail = line.trim_end();
if tail.is_empty() {
continue;
}
let (key, tail) = split_one(tail).unwrap();
let (timestamp, tail) = split_one(tail).unwrap();
let ts: Timestamp;
if let Some(f) = timestamp_format.as_ref() {
let n = chrono::NaiveDateTime::parse_from_str(×tamp, f)
.expect("parsing timestamp according to format");
ts = n
.and_utc()
.timestamp_nanos_opt()
.ok_or(crate::WriteFailure::UnableToParseTimestamp)? as Timestamp;
} else {
ts = timestamp.parse().expect("parsing timestamp");
}
row_format
.to_stored_format(ts, tail, &mut row_data)
.unwrap_or_else(|_| panic!("parsing values \"{}\"", tail));
tx.add_record_raw(&key, format, &row_data)?;
row_data.clear();
line.clear();
}
Ok(())
}
pub fn add_from_stream_with_fmt<R: std::io::BufRead>(
tx: &mut crate::CreateTx,
input: &mut R,
timestamp_format: Option<&str>,
) -> Result<(), crate::WriteFailure> {
let mut line = String::new();
let mut row_data = vec![];
while 0 != input.read_line(&mut line).unwrap() {
let tail = line.trim_end();
if tail.is_empty() {
continue;
}
let (key, tail) = split_one(tail).unwrap();
let (timestamp, tail) = split_one(tail).unwrap();
let ts: Timestamp;
if let Some(f) = timestamp_format.as_ref() {
let n = chrono::NaiveDateTime::parse_from_str(×tamp, f)
.expect("parsing timestamp according to format");
ts = n
.and_utc()
.timestamp_nanos_opt()
.ok_or(crate::WriteFailure::UnableToParseTimestamp)? as Timestamp;
} else {
ts = timestamp.parse().expect("parsing timestamp");
}
let (format, values) = split_one(tail).unwrap();
let row_format = parse_row_format(&format);
row_format
.to_stored_format(ts, values, &mut row_data)
.unwrap();
tx.add_record_raw(&key, &format, &row_data)?;
row_data.clear();
line.clear();
}
Ok(())
}
#[derive(Debug, Copy, Clone)]
pub enum PrintRecordFormat {
Yes,
No,
}
impl std::default::Default for PrintRecordFormat {
fn default() -> Self {
PrintRecordFormat::Yes
}
}
#[derive(Debug, Copy, Clone)]
pub enum PrintTimestamp<'a> {
Nanos,
Seconds,
FormatString(&'a str),
}
impl std::default::Default for PrintTimestamp<'static> {
fn default() -> Self {
PrintTimestamp::FormatString("%FT%T")
}
}
pub fn print_record<W: std::io::Write>(
record: &crate::Record,
out: &mut W,
print_timestamp: PrintTimestamp<'_>,
print_record_format: PrintRecordFormat,
column_selection: &choice_string::Selection,
) -> std::io::Result<()> {
let fmt_string = record.format();
let fmt = parse_row_format(fmt_string);
let key = record.key();
let ts = &record.raw()[0..8];
let value = &record.raw()[8..];
let ts: u64 = byteorder::BigEndian::read_u64(ts);
write!(out, "{}\t", escape_string::escape(key))?;
match print_timestamp {
PrintTimestamp::Nanos => write!(out, "{}", ts)?,
PrintTimestamp::Seconds => write!(out, "{}", ts / 1_000_000_000)?,
PrintTimestamp::FormatString(strf) => {
let ts = chrono::DateTime::from_timestamp(
(ts / 1_000_000_000) as i64,
(ts % 1_000_000_000) as u32,
)
.unwrap();
write!(out, "{}", ts.format(strf))?;
}
}
write!(out, "\t")?;
match print_record_format {
PrintRecordFormat::Yes => write!(out, "{}\t", fmt_string)?,
PrintRecordFormat::No => {}
}
let mut value = value;
let mut first = true;
for (idx, e) in fmt.elements().iter().enumerate() {
if column_selection.contains_item(idx + 1) {
if !first {
write!(out, " ")?;
}
first = false;
value = e.to_protocol_format(value, out)?;
} else {
value = e.to_protocol_format(value, &mut std::io::sink())?;
}
}
Ok(())
}