ClickHouse / clickhouse-rs

Official pure Rust typed client for ClickHouse DB
https://clickhouse.com
Apache License 2.0
322 stars 90 forks source link

Save vector of custom type error into String type in clickhouse #72

Open wexgjduv opened 1 year ago

wexgjduv commented 1 year ago

Hi, I want to save vector of Filters into monitor table:

#[derive(Debug, Serialize, Deserialize, Row)]
pub struct Filter {
    pub name: String,
    pub operator: String,
}
#[derive(Debug, Serialize, Deserialize, Row)]
pub struct Monitor {
    #[serde(with = "clickhouse::serde::uuid")]
    pub uuid: Uuid,
    pub name: String,
    // Use the custom `filter_serde` for the `filters` field
    // #[serde(with = "filter_serde")]
    pub filters: Vec<Filter>,
}

pub async fn create_table(client: &Client) -> Result<(), Box<dyn std::error::Error>> {
    client
        .query(
            "
            CREATE TABLE IF NOT EXISTS monitor(
                uuid UUID,
                name LowCardinality(String),
                filters Nullable(String)
            )
            ENGINE = MergeTree
            ORDER BY name
        ",
        )
        .execute()
        .await
        .map_err(|err: Error| err.into())
}

pub async fn insert_monitor(
    client: &Client,
    monitor: &Monitor,
) -> Result<(), Box<dyn std::error::Error>> {
    let mut insert = client.insert(table_name)?;
    insert.write(monitor).await?;
    insert.end().await?;
    Ok(())
}

let now = OffsetDateTime::now_utc();

let filter = Filter {
    name: "123".to_string(),
    operator: "=".to_string(),
};
let filters = vec![filter];

let monitor = Monitor{
    uuid: Uuid::new_v4(),
    name: "test".to_string(),
    filters: filters
}

let _ = insert_monitor(&client, &monitor).await?;

However, there's an error during the insertion.

Error: BadResponse("Code: 33. DB::Exception: Cannot read all data. Bytes read: 9. Bytes expected: 97.: (at row 2)\n: While executing BinaryRowInputFormat. (CANNOT_READ_ALL_DATA) (version 22.7.2.1)")

How to write a vector of custom type(Vec<Filter>) and insert into the table?

Do I need to write serialize and deserialize functions and specify with #[serde(with = "filter_serde")] in filters field?

Thanks.

loyd commented 1 year ago

Hello, I do not totally understand the problem. You're trying to insert Vec<String> into String. The schema should contain Array(String) or you can use serde(with) to somehow transform Vec<String> into String on your own.