Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 39 additions & 39 deletions src-crates/clickhouse/src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ use query::Value;
use std::str::FromStr;

pub(super) fn decode_value(val: String, datatype: &str) -> Value {
if val == "ᴺᵁᴸᴸ" && datatype.starts_with("nullable(") {
if val == "ᴺᵁᴸᴸ" && datatype.starts_with("Nullable(") {
return Value::Null;
}
match datatype {
"bool" | "nullable(bool)" => decode(val, Value::Bool),
"int8" | "nullable(int8)" => decode(val, Value::I8),
"uint8" | "nullable(uint8)" => decode(val, Value::U8),
"int16" | "nullable(int16)" => decode(val, Value::I16),
"uint16" | "nullable(uint16)" => decode(val, Value::U16),
"int32" | "nullable(int32)" => decode(val, Value::I32),
"uint32" | "nullable(uint32)" => decode(val, Value::U32),
"int64" | "nullable(int64)" => decode(val, Value::I64),
"uint64" | "nullable(uint64)" => decode(val, Value::U64),
"float32" | "nullable(float32)" => decode(val, Value::F32),
"float64" | "nullable(float64)" => decode(val, Value::F64),
"Bool" | "Nullable(Bool)" => decode(val, Value::Bool),
"Int8" | "Nullable(Int8)" => decode(val, Value::I8),
"UInt8" | "Nullable(UInt8)" => decode(val, Value::U8),
"Int16" | "Nullable(Int16)" => decode(val, Value::I16),
"UInt16" | "Nullable(UInt16)" => decode(val, Value::U16),
"Int32" | "Nullable(Int32)" => decode(val, Value::I32),
"UInt32" | "Nullable(UInt32)" => decode(val, Value::U32),
"Int64" | "Nullable(Int64)" => decode(val, Value::I64),
"UInt64" | "Nullable(UInt64)" => decode(val, Value::U64),
"Float32" | "Nullable(Float32)" => decode(val, Value::F32),
"Float64" | "Nullable(Float64)" => decode(val, Value::F64),
_ => Value::String(val),
}
}
Expand All @@ -36,104 +36,104 @@ mod tests {

#[test]
fn decode_value_null_for_nullable_type() {
assert_eq!(decode_value("ᴺᵁᴸᴸ".into(), "nullable(string)"), Value::Null);
assert_eq!(decode_value("ᴺᵁᴸᴸ".into(), "nullable(int32)"), Value::Null);
assert_eq!(decode_value("ᴺᵁᴸᴸ".into(), "nullable(bool)"), Value::Null);
assert_eq!(decode_value("ᴺᵁᴸᴸ".into(), "Nullable(String)"), Value::Null);
assert_eq!(decode_value("ᴺᵁᴸᴸ".into(), "Nullable(Int32)"), Value::Null);
assert_eq!(decode_value("ᴺᵁᴸᴸ".into(), "Nullable(Bool)"), Value::Null);
}

#[test]
fn decode_value_bool() {
assert_eq!(decode_value("true".into(), "bool"), Value::Bool(true));
assert_eq!(decode_value("false".into(), "bool"), Value::Bool(false));
assert_eq!(decode_value("true".into(), "Bool"), Value::Bool(true));
assert_eq!(decode_value("false".into(), "Bool"), Value::Bool(false));
assert_eq!(
decode_value("true".into(), "nullable(bool)"),
decode_value("true".into(), "Nullable(Bool)"),
Value::Bool(true)
);
}

#[test]
fn decode_value_signed_integers() {
assert_eq!(decode_value("127".into(), "int8"), Value::I8(127));
assert_eq!(decode_value("32767".into(), "int16"), Value::I16(32767));
assert_eq!(decode_value("127".into(), "Int8"), Value::I8(127));
assert_eq!(decode_value("32767".into(), "Int16"), Value::I16(32767));
assert_eq!(
decode_value("2147483647".into(), "int32"),
decode_value("2147483647".into(), "Int32"),
Value::I32(2147483647)
);
assert_eq!(
decode_value("9223372036854775807".into(), "int64"),
decode_value("9223372036854775807".into(), "Int64"),
Value::I64(i64::MAX)
);
}

#[test]
fn decode_value_unsigned_integers() {
assert_eq!(decode_value("255".into(), "uint8"), Value::U8(255));
assert_eq!(decode_value("65535".into(), "uint16"), Value::U16(65535));
assert_eq!(decode_value("255".into(), "UInt8"), Value::U8(255));
assert_eq!(decode_value("65535".into(), "UInt16"), Value::U16(65535));
assert_eq!(
decode_value("4294967295".into(), "uint32"),
decode_value("4294967295".into(), "UInt32"),
Value::U32(4294967295)
);
assert_eq!(
decode_value("18446744073709551615".into(), "uint64"),
decode_value("18446744073709551615".into(), "UInt64"),
Value::U64(u64::MAX)
);
}

#[test]
fn decode_value_floats() {
assert_eq!(decode_value("3.14".into(), "float32"), Value::F32(3.14));
assert_eq!(decode_value("3.14".into(), "Float32"), Value::F32(3.14));
assert_eq!(
decode_value("3.141592653589793".into(), "float64"),
decode_value("3.141592653589793".into(), "Float64"),
Value::F64(3.141592653589793)
);
}

#[test]
fn decode_value_nullable_numeric_types() {
assert_eq!(decode_value("42".into(), "nullable(int32)"), Value::I32(42));
assert_eq!(decode_value("-1".into(), "nullable(int8)"), Value::I8(-1));
assert_eq!(decode_value("42".into(), "Nullable(Int32)"), Value::I32(42));
assert_eq!(decode_value("-1".into(), "Nullable(Int8)"), Value::I8(-1));
assert_eq!(
decode_value("100".into(), "nullable(uint64)"),
decode_value("100".into(), "Nullable(UInt64)"),
Value::U64(100)
);
assert_eq!(
decode_value("2.5".into(), "nullable(float32)"),
decode_value("2.5".into(), "Nullable(Float32)"),
Value::F32(2.5)
);
}

#[test]
fn decode_value_unknown_type_returns_string() {
assert_eq!(
decode_value("2024-01-01".into(), "date"),
decode_value("2024-01-01".into(), "Date"),
Value::String("2024-01-01".into())
);
assert_eq!(
decode_value("hello".into(), "fixedstring(10)"),
decode_value("hello".into(), "FixedString(10)"),
Value::String("hello".into())
);
assert_eq!(
decode_value("[1,2,3]".into(), "array(uint32)"),
decode_value("[1,2,3]".into(), "Array(UInt32)"),
Value::String("[1,2,3]".into())
);
}

#[test]
fn decode_value_unparseable_falls_back_to_string() {
assert_eq!(
decode_value("not_a_number".into(), "int32"),
decode_value("not_a_number".into(), "Int32"),
Value::String("not_a_number".into())
);
assert_eq!(
decode_value("not_a_bool".into(), "bool"),
decode_value("not_a_bool".into(), "Bool"),
Value::String("not_a_bool".into())
);
assert_eq!(
decode_value("256".into(), "uint8"),
decode_value("256".into(), "UInt8"),
Value::String("256".into())
);
assert_eq!(
decode_value("-1".into(), "uint32"),
decode_value("-1".into(), "UInt32"),
Value::String("-1".into())
);
}
Expand Down
45 changes: 40 additions & 5 deletions src-crates/clickhouse/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ impl Connection {
.into_iter()
.map(|meta| QueryColumn {
name: meta.name,
datatype: meta.r#type.to_lowercase(),
datatype: meta.r#type,
})
.collect::<Vec<_>>();
let rows = query
Expand Down Expand Up @@ -258,13 +258,15 @@ mod tests {
.collect()
}

const PASSWORD: &str = "";

fn connection() -> Connection {
Connection::open_with(Config {
https: false,
host: "localhost".into(),
port: 8123,
user: "default".into(),
password: "".into(),
password: PASSWORD.into(),
database: "".into(),
proxy: None,
})
Expand All @@ -277,7 +279,7 @@ mod tests {
host: "localhost".into(),
port: 8123,
user: "default".into(),
password: "".into(),
password: PASSWORD.into(),
database: database.into(),
proxy: None,
})
Expand Down Expand Up @@ -423,19 +425,46 @@ mod tests {
.unwrap();

assert_eq!(result.rows.len(), 1);
let cols = &result.columns;
let row = &result.rows[0];

assert_eq!(cols[0].datatype, "Bool");
assert_eq!(row[0], Value::Bool(true));

assert_eq!(cols[1].datatype, "Bool");
assert_eq!(row[1], Value::Bool(false));

assert_eq!(cols[2].datatype, "Int8");
assert_eq!(row[2], Value::I8(127));

assert_eq!(cols[3].datatype, "UInt8");
assert_eq!(row[3], Value::U8(255));

assert_eq!(cols[4].datatype, "Int16");
assert_eq!(row[4], Value::I16(32767));

assert_eq!(cols[5].datatype, "UInt16");
assert_eq!(row[5], Value::U16(65535));

assert_eq!(cols[6].datatype, "Int32");
assert_eq!(row[6], Value::I32(2147483647));

assert_eq!(cols[7].datatype, "UInt32");
assert_eq!(row[7], Value::U32(4294967295));

assert_eq!(cols[8].datatype, "Int64");
assert_eq!(row[8], Value::I64(9223372036854775807));

assert_eq!(cols[9].datatype, "UInt64");
assert_eq!(row[9], Value::U64(18446744073709551615));

assert_eq!(cols[10].datatype, "Float32");
assert_eq!(row[10], Value::F32(1.5));

assert_eq!(cols[11].datatype, "Float64");
assert_eq!(row[11], Value::F64(1.5));

assert_eq!(cols[12].datatype, "String");
assert_eq!(row[12], Value::String("hello world".into()));
}

Expand All @@ -455,10 +484,16 @@ mod tests {
.unwrap();

assert_eq!(result.rows.len(), 1);
let cols = &result.columns;
let row = &result.rows[0];
assert_eq!(row[0], Value::Null);
assert_eq!(cols[0].datatype, "Nullable(Int32)");

assert_eq!(row[1], Value::Null);
assert_eq!(cols[1].datatype, "Nullable(String)");

assert_eq!(row[2], Value::Null);
assert_eq!(cols[2].datatype, "Nullable(UInt8)");
}

#[tokio::test]
Expand Down Expand Up @@ -495,8 +530,8 @@ mod tests {
.await
.unwrap();

assert_eq!(result.columns[0].datatype, "int32");
assert_eq!(result.columns[1].datatype, "nullable(uint64)");
assert_eq!(result.columns[0].datatype, "Int32");
assert_eq!(result.columns[1].datatype, "Nullable(UInt64)");
Comment on lines +533 to +534
}

#[tokio::test]
Expand Down