From ed5417388c269373b84253038c9d28232b781fca Mon Sep 17 00:00:00 2001 From: wyhaya Date: Wed, 3 Jun 2026 16:32:26 +0800 Subject: [PATCH] Fix ClickHouse datatype handling and update test cases for consistency --- src-crates/clickhouse/src/decode.rs | 78 ++++++++++++++--------------- src-crates/clickhouse/src/lib.rs | 45 +++++++++++++++-- 2 files changed, 79 insertions(+), 44 deletions(-) diff --git a/src-crates/clickhouse/src/decode.rs b/src-crates/clickhouse/src/decode.rs index 78cd8c7..42b6317 100644 --- a/src-crates/clickhouse/src/decode.rs +++ b/src-crates/clickhouse/src/decode.rs @@ -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), } } @@ -36,68 +36,68 @@ 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) ); } @@ -105,15 +105,15 @@ mod tests { #[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()) ); } @@ -121,19 +121,19 @@ mod tests { #[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()) ); } diff --git a/src-crates/clickhouse/src/lib.rs b/src-crates/clickhouse/src/lib.rs index 5cd5f52..315a527 100644 --- a/src-crates/clickhouse/src/lib.rs +++ b/src-crates/clickhouse/src/lib.rs @@ -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::>(); let rows = query @@ -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, }) @@ -277,7 +279,7 @@ mod tests { host: "localhost".into(), port: 8123, user: "default".into(), - password: "".into(), + password: PASSWORD.into(), database: database.into(), proxy: None, }) @@ -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())); } @@ -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] @@ -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)"); } #[tokio::test]