use std::io::Cursor;
use crate::Result;
use crate::{
Date, DateTime, DynDateTime64, i256,
types::{DeserializerState, SerializerState},
u256,
values::{self, Value},
};
#[cfg(feature = "bfloat16")]
use half::bf16;
use uuid::Uuid;
use super::Type;
async fn roundtrip_values(type_: &Type, values: &[Value]) -> Result<Vec<Value>> {
let mut results = vec![];
for revision in [54491, 54493] {
let mut output = vec![];
let mut state = SerializerState::new(revision);
let prefix_values: &[Value] = if type_.contains_dynamic() {
values
} else {
&[]
};
type_
.serialize_prefix(prefix_values, &mut output, &mut state)
.await?;
type_
.serialize_column(values.to_vec(), &mut output, &mut state)
.await?;
let length = output.len() as u64;
let mut input = Cursor::new(output);
let mut state = DeserializerState::new(revision);
type_.deserialize_prefix(&mut input, &mut state).await?;
let deserialized = type_
.deserialize_column(&mut input, values.len(), &mut state)
.await?;
assert_eq!(
input.position(),
length,
"{type_} at {revision}: bytes left"
);
results.push(deserialized);
}
assert_eq!(results[0], results[1], "{type_}: revisions disagree");
Ok(results.pop().unwrap())
}
#[tokio::test]
async fn roundtrip_u8() {
let values = &[Value::UInt8(12), Value::UInt8(24), Value::UInt8(30)];
assert_eq!(
&values[..],
roundtrip_values(&Type::UInt8, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_u16() {
let values = &[Value::UInt16(12), Value::UInt16(24), Value::UInt16(30000)];
assert_eq!(
&values[..],
roundtrip_values(&Type::UInt16, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_u32() {
let values = &[Value::UInt32(12), Value::UInt32(24), Value::UInt32(900000)];
assert_eq!(
&values[..],
roundtrip_values(&Type::UInt32, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_u64() {
let values = &[
Value::UInt64(12),
Value::UInt64(24),
Value::UInt64(9000000000),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::UInt64, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_u128() {
let values = &[
Value::UInt128(12),
Value::UInt128(24),
Value::UInt128(9000000000),
Value::UInt128(9000000000u128 * 9000000000),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::UInt128, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_u256() {
let values = &[
Value::UInt256(u256([0u8; 32])),
Value::UInt256(u256([7u8; 32])),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::UInt256, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_i8() {
let values = &[
Value::Int8(12),
Value::Int8(24),
Value::Int8(30),
Value::Int8(-30),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Int8, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_i16() {
let values = &[
Value::Int16(12),
Value::Int16(24),
Value::Int16(30000),
Value::Int16(-30000),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Int16, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_i32() {
let values = &[
Value::Int32(12),
Value::Int32(24),
Value::Int32(900000),
Value::Int32(-900000),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Int32, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_i64() {
let values = &[
Value::Int64(12),
Value::Int64(24),
Value::Int64(9000000000),
Value::Int64(-9000000000),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Int64, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_i128() {
let values = &[
Value::Int128(12),
Value::Int128(24),
Value::Int128(9000000000),
Value::Int128(9000000000i128 * 9000000000),
Value::Int128(-9000000000i128 * 9000000000),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Int128, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_i256() {
let values = &[
Value::Int256(i256([0u8; 32])),
Value::Int256(i256([7u8; 32])),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Int256, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_f32() {
let values = &[
Value::Float32(1.0_f32),
Value::Float32(0.0_f32),
Value::Float32(100.0_f32),
Value::Float32(100000.0_f32),
Value::Float32(1000000.0_f32),
Value::Float32(-1000000.0_f32),
Value::Float32(f32::NAN),
Value::Float32(f32::INFINITY),
Value::Float32(f32::NEG_INFINITY),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Float32, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_f64() {
let values = &[
Value::Float64(1.0_f64),
Value::Float64(0.0_f64),
Value::Float64(100.0_f64),
Value::Float64(100000.0_f64),
Value::Float64(1000000.0_f64),
Value::Float64(-1000000.0_f64),
Value::Float64(f64::NAN),
Value::Float64(f64::INFINITY),
Value::Float64(f64::NEG_INFINITY),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Float64, &values[..]).await.unwrap()
);
}
#[tokio::test]
#[cfg(feature = "bfloat16")]
async fn roundtrip_bf16() {
let values = &[
Value::BFloat16(bf16::from_f32(1.00)),
Value::BFloat16(bf16::from_f32(0.0)),
Value::BFloat16(bf16::from_f32(100.0)),
Value::BFloat16(bf16::from_f32(100000.0)),
Value::BFloat16(bf16::from_f32(1000000.0)),
Value::BFloat16(bf16::from_f32(-1000000.0)),
Value::BFloat16(bf16::NAN),
Value::BFloat16(bf16::INFINITY),
Value::BFloat16(bf16::NEG_INFINITY),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::BFloat16, &values[..])
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_d32() {
let values = &[
Value::Decimal32(5, 12),
Value::Decimal32(5, 24),
Value::Decimal32(5, 900000),
Value::Decimal32(5, -900000),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Decimal32(5), &values[..])
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_d64() {
let values = &[
Value::Decimal64(5, 12),
Value::Decimal64(5, 24),
Value::Decimal64(5, 9000000000),
Value::Decimal64(5, -9000000000),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Decimal64(5), &values[..])
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_d128() {
let values = &[
Value::Decimal128(5, 12),
Value::Decimal128(5, 24),
Value::Decimal128(5, 9000000000),
Value::Decimal128(5, 9000000000i128 * 9000000000),
Value::Decimal128(5, -9000000000i128 * 9000000000),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Decimal128(5), &values[..])
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_d256() {
let values = &[
Value::Decimal256(5, i256([0u8; 32])),
Value::Decimal256(5, i256([7u8; 32])),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Decimal256(5), &values[..])
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_null_int() {
let values = &[
Value::UInt32(35),
Value::UInt32(90),
Value::Null,
Value::UInt32(120),
Value::UInt32(10000),
Value::Null,
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Nullable(Box::new(Type::UInt32)), &values[..])
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_string() {
let values = &[
Value::string(""),
Value::string("t"),
Value::string("test"),
Value::string("TESTST"),
Value::string("日本語"),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::String, &values[..]).await.unwrap()
);
assert_eq!(
&values[..],
roundtrip_values(&Type::FixedString(32), &values[..])
.await
.unwrap()
);
assert_ne!(
&values[..],
roundtrip_values(&Type::FixedString(3), &values[..])
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_null_string() {
let values = &[
Value::string(""),
Value::Null,
Value::string("t"),
Value::string("test"),
Value::Null,
Value::string("TESTST"),
Value::string("日本語"),
Value::Null,
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Nullable(Box::new(Type::String)), &values[..])
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_uuid() {
let values = &[
Value::Uuid(Uuid::from_u128(0)),
Value::Uuid(Uuid::from_u128(1)),
Value::Uuid(Uuid::from_u128(456345634563456)),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Uuid, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_date() {
let values = &[
Value::Date(Date(0)),
Value::Date(Date(3234)),
Value::Date(Date(45345)),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Date, &values[..]).await.unwrap()
);
}
#[tokio::test]
async fn roundtrip_datetime() {
let values = &[
Value::DateTime(DateTime(chrono_tz::UTC, 0)),
Value::DateTime(DateTime(chrono_tz::UTC, 323463434)),
Value::DateTime(DateTime(chrono_tz::UTC, 45345345)),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::DateTime(chrono_tz::UTC), &values[..])
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_datetime64() {
let values = &[
Value::DateTime64(DynDateTime64(chrono_tz::UTC, 0, 3)),
Value::DateTime64(DynDateTime64(chrono_tz::UTC, 32346345634, 3)),
Value::DateTime64(DynDateTime64(chrono_tz::UTC, 4534564345, 3)),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::DateTime64(3, chrono_tz::UTC), &values[..])
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_array() {
let values = &[
Value::Array(vec![]),
Value::Array(vec![Value::UInt32(0)]),
Value::Array(vec![Value::UInt32(1), Value::UInt32(2), Value::UInt32(3)]),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Array(Box::new(Type::UInt32)), &values[..])
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_array2() {
let values = &[
Value::Array(vec![Value::Array(vec![])]),
Value::Array(vec![Value::Array(vec![Value::UInt32(1)])]),
Value::Array(vec![
Value::Array(vec![Value::UInt32(2)]),
Value::Array(vec![Value::UInt32(3)]),
]),
Value::Array(vec![
Value::Array(vec![Value::UInt32(4), Value::UInt32(5)]),
Value::Array(vec![Value::UInt32(6), Value::UInt32(7)]),
]),
Value::Array(vec![Value::Array(vec![Value::UInt32(8)])]),
];
assert_eq!(
&values[..],
roundtrip_values(
&Type::Array(Box::new(Type::Array(Box::new(Type::UInt32)))),
&values[..]
)
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_tuple() {
let values = &[
Value::Tuple(vec![Value::UInt32(1), Value::UInt16(2)]),
Value::Tuple(vec![Value::UInt32(3), Value::UInt16(4)]),
Value::Tuple(vec![Value::UInt32(4), Value::UInt16(5)]),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::Tuple(vec![Type::UInt32, Type::UInt16]), &values[..])
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_2tuple() {
let values = &[
Value::Tuple(vec![
Value::UInt32(1),
Value::Tuple(vec![Value::UInt32(1), Value::UInt16(2)]),
]),
Value::Tuple(vec![
Value::UInt32(3),
Value::Tuple(vec![Value::UInt32(3), Value::UInt16(4)]),
]),
Value::Tuple(vec![
Value::UInt32(4),
Value::Tuple(vec![Value::UInt32(4), Value::UInt16(5)]),
]),
];
assert_eq!(
&values[..],
roundtrip_values(
&Type::Tuple(vec![
Type::UInt32,
Type::Tuple(vec![Type::UInt32, Type::UInt16])
]),
&values[..]
)
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_array_tuple() {
let values = &[
Value::Array(vec![
Value::Tuple(vec![Value::UInt32(1), Value::UInt16(2)]),
Value::Tuple(vec![Value::UInt32(3), Value::UInt16(4)]),
]),
Value::Array(vec![Value::Tuple(vec![Value::UInt32(5), Value::UInt16(6)])]),
Value::Array(vec![]),
];
assert_eq!(
&values[..],
roundtrip_values(
&Type::Array(Box::new(Type::Tuple(vec![Type::UInt32, Type::UInt16]))),
&values[..]
)
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_tuple_array() {
let values = &[
Value::Tuple(vec![Value::Array(vec![]), Value::Array(vec![])]),
Value::Tuple(vec![
Value::Array(vec![Value::UInt32(1)]),
Value::Array(vec![]),
]),
Value::Tuple(vec![
Value::Array(vec![]),
Value::Array(vec![Value::UInt16(2)]),
]),
Value::Tuple(vec![
Value::Array(vec![Value::UInt32(3)]),
Value::Array(vec![Value::UInt16(4)]),
]),
Value::Tuple(vec![
Value::Array(vec![Value::UInt32(5), Value::UInt32(6)]),
Value::Array(vec![Value::UInt16(7), Value::UInt16(8)]),
]),
];
assert_eq!(
&values[..],
roundtrip_values(
&Type::Tuple(vec![
Type::Array(Box::new(Type::UInt32)),
Type::Array(Box::new(Type::UInt16))
]),
&values[..]
)
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_array_nulls() {
let values = &[
Value::Array(vec![]),
Value::Array(vec![Value::Null]),
Value::Array(vec![Value::UInt32(0), Value::Null]),
Value::Array(vec![Value::Null, Value::UInt32(0)]),
Value::Array(vec![
Value::Null,
Value::Null,
Value::UInt32(1),
Value::UInt32(2),
Value::Null,
Value::UInt32(3),
]),
];
assert_eq!(
&values[..],
roundtrip_values(
&Type::Array(Box::new(Type::Nullable(Box::new(Type::UInt32)))),
&values[..]
)
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_map() {
let values = &[
Value::Map(vec![], vec![]),
Value::Map(vec![Value::UInt32(1)], vec![Value::UInt16(2)]),
Value::Map(
vec![Value::UInt32(5), Value::UInt32(3)],
vec![Value::UInt16(6), Value::UInt16(4)],
),
];
assert_eq!(
&values[..],
roundtrip_values(
&Type::Map(Box::new(Type::UInt32), Box::new(Type::UInt16)),
&values[..]
)
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_low_cardinality_string() {
let values = &[
Value::string(""),
Value::string("abc"),
Value::string("abc"),
Value::string("bcd"),
Value::string("bcd2"),
Value::string("abc"),
Value::string("abc"),
Value::string("abc"),
Value::string("abc"),
Value::string("abc"),
Value::string("abc"),
Value::string("abc"),
Value::string("abc"),
Value::string("abc"),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::LowCardinality(Box::new(Type::String)), &values[..])
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_low_cardinality_string_array() {
let values = &[
Value::Array(vec![]),
Value::Array(vec![Value::string("")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("bcd")]),
Value::Array(vec![Value::string("bcd2")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
];
assert_eq!(
&values[..],
roundtrip_values(
&Type::Array(Box::new(Type::LowCardinality(Box::new(Type::String)))),
&values[..]
)
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_low_cardinality_string_map() {
let values = &[
Value::Map(vec![Value::string("")], vec![Value::UInt32(1)]),
Value::Map(vec![Value::string("abc")], vec![Value::UInt32(1)]),
Value::Map(vec![Value::string("abc")], vec![Value::UInt32(1)]),
Value::Map(vec![Value::string("bcd")], vec![Value::UInt32(1)]),
Value::Map(vec![Value::string("bcd2")], vec![Value::UInt32(1)]),
Value::Map(vec![Value::string("abc")], vec![Value::UInt32(1)]),
Value::Map(vec![Value::string("abc")], vec![Value::UInt32(1)]),
Value::Map(vec![Value::string("abc")], vec![Value::UInt32(1)]),
Value::Map(vec![Value::string("abc")], vec![Value::UInt32(1)]),
Value::Map(vec![Value::string("abc")], vec![Value::UInt32(1)]),
Value::Map(vec![Value::string("abc")], vec![Value::UInt32(1)]),
Value::Map(vec![Value::string("abc")], vec![Value::UInt32(1)]),
Value::Map(vec![Value::string("abc")], vec![Value::UInt32(1)]),
Value::Map(vec![Value::string("abc")], vec![Value::UInt32(1)]),
];
assert_eq!(
&values[..],
roundtrip_values(
&Type::Map(
Box::new(Type::LowCardinality(Box::new(Type::String))),
Box::new(Type::UInt32)
),
&values[..]
)
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_low_cardinality_string_null() {
let values = &[
Value::string(""),
Value::Null,
Value::string("abc"),
Value::string("abc"),
Value::string("bcd"),
Value::string("bcd2"),
Value::Null,
Value::string("abc"),
Value::string("abc"),
Value::string("abc"),
Value::string("abc"),
Value::Null,
Value::string("abc"),
Value::string("abc"),
Value::string("abc"),
Value::string("abc"),
Value::Null,
Value::string("abc"),
];
assert_eq!(
&values[..],
roundtrip_values(
&Type::LowCardinality(Box::new(Type::Nullable(Box::new(Type::String)))),
&values[..]
)
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_low_cardinality_array_null() {
let values = &[
Value::Array(vec![Value::string("")]),
Value::Array(vec![Value::Null]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("bcd")]),
Value::Array(vec![Value::string("bcd2")]),
Value::Array(vec![Value::Null]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::Null]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::Null]),
Value::Array(vec![Value::string("abc")]),
];
assert_eq!(
&values[..],
roundtrip_values(
&Type::Array(Box::new(Type::LowCardinality(Box::new(Type::Nullable(
Box::new(Type::String)
))))),
&values[..]
)
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_array_null() {
let values = &[
Value::Array(vec![Value::string("")]),
Value::Array(vec![Value::Null]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("bcd")]),
Value::Array(vec![Value::string("bcd2")]),
Value::Array(vec![Value::Null]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::Null]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::string("abc")]),
Value::Array(vec![Value::Null]),
Value::Array(vec![Value::string("abc")]),
];
assert_eq!(
&values[..],
roundtrip_values(
&Type::Array(Box::new(Type::Nullable(Box::new(Type::String)))),
&values[..]
)
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_geo() {
let point = |x| values::Point([x, x + 2.0]);
let values = &[Value::Point(point(1.0)), Value::Point(point(3.0))];
assert_eq!(
&values[..],
roundtrip_values(&Type::Point, &values[..]).await.unwrap()
);
let ring = |x| values::Ring(vec![point(x), point(2.0 * x)]);
let values = &[Value::Ring(ring(1.0)), Value::Ring(ring(3.0))];
assert_eq!(
&values[..],
roundtrip_values(&Type::Ring, &values[..]).await.unwrap()
);
let polygon = |x| values::Polygon(vec![ring(x), ring(2.0 * x)]);
let values = &[Value::Polygon(polygon(1.0)), Value::Polygon(polygon(3.0))];
assert_eq!(
&values[..],
roundtrip_values(&Type::Polygon, &values[..]).await.unwrap()
);
let multipolygon = |x| values::MultiPolygon(vec![polygon(x), polygon(2.0 * x)]);
let values = &[
Value::MultiPolygon(multipolygon(1.0)),
Value::MultiPolygon(multipolygon(3.0)),
];
assert_eq!(
&values[..],
roundtrip_values(&Type::MultiPolygon, &values[..])
.await
.unwrap()
);
}
#[tokio::test]
async fn roundtrip_new_scalar_types() {
use crate::Date32;
for (type_, values) in [
(Type::Bool, vec![Value::Bool(true), Value::Bool(false)]),
(
Type::Date32,
vec![
Value::Date32(Date32(-25567)),
Value::Date32(Date32(120_000)),
],
),
(Type::Time, vec![Value::Time(-5), Value::Time(90_000)]),
(
Type::Time64(6),
vec![Value::Time64(6, -1), Value::Time64(6, 86_400_000_000)],
),
(
Type::Interval(super::IntervalKind::Day),
vec![Value::Int64(-3), Value::Int64(7)],
),
(Type::Nothing, vec![Value::Null, Value::Null]),
(
Type::SimpleAggregateFunction("sum".into(), Box::new(Type::UInt64)),
vec![Value::UInt64(1), Value::UInt64(2)],
),
(
Type::Json(String::new()),
vec![Value::string("{\"a\":1}"), Value::string("{}")],
),
] {
assert_eq!(
roundtrip_values(&type_, &values).await.unwrap(),
values,
"{type_}"
);
}
}
#[tokio::test]
async fn roundtrip_strings_in_every_container() {
let s = |x: &str| Value::string(x);
for (type_, values) in [
("String", vec![s("ab"), s(""), s("c\0d"), s("é")]),
("Nullable(String)", vec![s("x"), Value::Null, s("")]),
(
"Array(String)",
vec![Value::Array(vec![s("a"), s("bc")]), Value::Array(vec![])],
),
(
"Map(String, String)",
vec![Value::Map(vec![s("k")], vec![s("v")])],
),
(
"Tuple(a String, b UInt8)",
vec![Value::Tuple(vec![s("t"), Value::UInt8(1)])],
),
("LowCardinality(String)", vec![s("a"), s("b"), s("a")]),
(
"LowCardinality(Nullable(String))",
vec![s("a"), Value::Null],
),
(
"Array(LowCardinality(String))",
vec![Value::Array(vec![s("x"), s("x")])],
),
] {
let type_: Type = type_.parse().unwrap();
assert_eq!(
roundtrip_values(&type_, &values).await.unwrap(),
values,
"{type_}"
);
}
}
#[tokio::test]
async fn roundtrip_variant_and_dynamic() {
use crate::DynamicValue;
let dynamic = |t: Type, v: Value| Value::Dynamic(Box::new(DynamicValue::new(t, v)));
let variant: Type = "Variant(Array(UInt8), String, UInt64)".parse().unwrap();
let values = vec![
dynamic(Type::UInt64, Value::UInt64(42)),
Value::Null,
dynamic(Type::String, Value::string("abc")),
dynamic(
Type::Array(Box::new(Type::UInt8)),
Value::Array(vec![Value::UInt8(1)]),
),
];
assert_eq!(roundtrip_values(&variant, &values).await.unwrap(), values);
let plain = vec![Value::UInt64(7), Value::string("s")];
let read = roundtrip_values(&variant, &plain).await.unwrap();
assert_eq!(read[0], dynamic(Type::UInt64, Value::UInt64(7)));
assert_eq!(read[1], dynamic(Type::String, Value::string("s")));
let values = vec![
dynamic(Type::Int32, Value::Int32(-1)),
Value::Null,
dynamic(Type::String, Value::string("x")),
dynamic(Type::Int32, Value::Int32(5)),
dynamic(
"Array(Nullable(String))".parse().unwrap(),
Value::Array(vec![Value::Null]),
),
];
for type_ in [
"Dynamic",
"Dynamic(max_types=4)",
"Array(Dynamic)",
"Tuple(Dynamic, UInt8)",
] {
let type_: Type = type_.parse().unwrap();
let values = match &type_ {
Type::Array(_) => vec![Value::Array(values.clone()), Value::Array(vec![])],
Type::Tuple(_) => values
.iter()
.map(|x| Value::Tuple(vec![x.clone(), Value::UInt8(1)]))
.collect(),
_ => values.clone(),
};
assert_eq!(
roundtrip_values(&type_, &values).await.unwrap(),
values,
"{type_}"
);
}
}
#[tokio::test]
async fn roundtrip_geometry() {
use crate::{DynamicValue, Point, Polygon, Ring};
let dynamic = |t: Type, v: Value| Value::Dynamic(Box::new(DynamicValue::new(t, v)));
let ring = Ring(vec![Point([1.0, 2.0]), Point([3.0, 4.0])]);
let values = vec![
dynamic(Type::Point, Value::Point(Point([1.5, -2.5]))),
dynamic(Type::LineString, Value::Ring(ring.clone())),
dynamic(Type::Ring, Value::Ring(ring.clone())),
dynamic(
Type::MultiLineString,
Value::Polygon(Polygon(vec![ring.clone()])),
),
Value::Null,
];
assert_eq!(
roundtrip_values(&Type::Geometry, &values).await.unwrap(),
values
);
}