use std::sync::Arc;
use arrow_array::{LargeStringArray, RecordBatch};
use arrow_schema::Schema;
use reifydb_codec::json::{
from::{parse_json_value, parse_value},
none_marker,
to::convert_frames,
};
use reifydb_value::value::{
Value,
frame::frame::Frame,
value_type::{ValueType, field::named},
};
fn option_utf8() -> ValueType {
ValueType::Option(Box::new(ValueType::Utf8))
}
fn frame_with(values: Vec<&str>, defined: &[bool]) -> Frame {
let array = LargeStringArray::from(
values.into_iter()
.zip(defined)
.map(|(v, &d)| d.then(|| v.to_string()))
.collect::<Vec<Option<String>>>(),
);
let (field, array) = named("value", option_utf8().into(), Arc::new(array));
Frame::from(RecordBatch::try_new(Arc::new(Schema::new(vec![field])), vec![array]).unwrap())
}
#[test]
fn an_empty_payload_on_an_option_utf8_parses_as_the_empty_string() {
assert_eq!(parse_value(&option_utf8(), ""), Ok(Value::Utf8(String::new())));
}
#[test]
fn only_the_none_marker_parses_as_none_on_an_option_utf8() {
assert_eq!(parse_value(&option_utf8(), &none_marker(0)), Ok(Value::none_of(ValueType::Utf8)));
}
#[test]
fn an_empty_string_and_a_none_render_as_different_payloads() {
let frames = convert_frames(&[frame_with(vec!["", ""], &[true, false])]).unwrap();
let payload = &frames[0].columns[0].payload;
assert_eq!(payload[0], "", "a present empty string must render as an empty payload");
assert_eq!(payload[1], none_marker(0), "an absent value must render as the none marker");
assert_ne!(payload[0], payload[1]);
}
#[test]
fn an_empty_string_and_a_none_survive_the_render_and_parse_round_trip() {
let frames = convert_frames(&[frame_with(vec!["", ""], &[true, false])]).unwrap();
let column = &frames[0].columns[0];
assert_eq!(parse_json_value(&column.r#type.0, &column.payload[0]), Ok(Value::Utf8(String::new())));
assert_eq!(parse_json_value(&column.r#type.0, &column.payload[1]), Ok(Value::none_of(ValueType::Utf8)));
}