forked from suharev7/clickhouse-rs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
a way to pass row into a block (suharev7#48)
- Loading branch information
Showing
21 changed files
with
499 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
[package] | ||
name = "clickhouse-rs" | ||
version = "0.1.14" | ||
version = "0.1.15" | ||
authors = ["Mikhail Sukharev <[email protected]>"] | ||
license = "MIT" | ||
homepage = "https://github.com/suharev7/clickhouse-rs" | ||
|
@@ -34,4 +34,4 @@ lazy_static = "1.3.0" | |
|
||
[dev-dependencies] | ||
env_logger = "0.6.2" | ||
rand = "0.7.0" | ||
rand = "0.7.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
use std::borrow::Cow; | ||
|
||
use chrono_tz::Tz; | ||
|
||
use crate::{ | ||
Block, | ||
errors::{Error, FromSqlError}, | ||
types::{ | ||
block::ColumnIdx, | ||
column::{ArcColumnWrapper, ColumnData, Either}, | ||
Column, | ||
Value | ||
}, | ||
}; | ||
|
||
pub trait RowBuilder { | ||
fn apply(self, block: &mut Block) -> Result<(), Error>; | ||
} | ||
|
||
pub struct RNil; | ||
|
||
pub struct RCons<T> | ||
where | ||
T: RowBuilder, | ||
{ | ||
key: Cow<'static, str>, | ||
value: Value, | ||
tail: T, | ||
} | ||
|
||
impl RNil { | ||
pub fn put(self, key: Cow<'static, str>, value: Value) -> RCons<Self> { | ||
RCons { | ||
key, | ||
value, | ||
tail: RNil, | ||
} | ||
} | ||
} | ||
|
||
impl<T> RCons<T> | ||
where | ||
T: RowBuilder, | ||
{ | ||
pub fn put(self, key: Cow<'static, str>, value: Value) -> RCons<Self> { | ||
RCons { | ||
key, | ||
value, | ||
tail: self, | ||
} | ||
} | ||
} | ||
|
||
impl RowBuilder for RNil { | ||
#[inline(always)] | ||
fn apply(self, _block: &mut Block) -> Result<(), Error> { | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl<T> RowBuilder for RCons<T> | ||
where | ||
T: RowBuilder, | ||
{ | ||
#[inline(always)] | ||
fn apply(self, block: &mut Block) -> Result<(), Error> { | ||
put_param(self.key, self.value, block)?; | ||
self.tail.apply(block) | ||
} | ||
} | ||
|
||
impl RowBuilder for Vec<(String, Value)> { | ||
fn apply(self, block: &mut Block) -> Result<(), Error> { | ||
for (k, v) in self { | ||
put_param(k.into(), v, block)?; | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
fn put_param(key: Cow<'static, str>, value: Value, block: &mut Block) -> Result<(), Error> { | ||
let col_index = match key.as_ref().get_index(&block.columns) { | ||
Ok(col_index) => col_index, | ||
Err(Error::FromSql(FromSqlError::OutOfRange)) => { | ||
if block.row_count() <= 1 { | ||
let sql_type = From::from(value.clone()); | ||
|
||
let timezone = extract_timezone(&value); | ||
|
||
let column = Column { | ||
name: key.clone().into(), | ||
data: ColumnData::from_type::<ArcColumnWrapper>(sql_type, timezone)?, | ||
}; | ||
|
||
block.columns.push(column); | ||
return put_param(key, value, block); | ||
} else { | ||
return Err(Error::FromSql(FromSqlError::OutOfRange)); | ||
} | ||
} | ||
Err(err) => return Err(err), | ||
}; | ||
|
||
block.columns[col_index].push(value); | ||
Ok(()) | ||
} | ||
|
||
fn extract_timezone(value: &Value) -> Tz { | ||
match value { | ||
Value::Date(_, tz) => *tz, | ||
Value::DateTime(_, tz) => *tz, | ||
Value::Nullable(Either::Right(d)) => { | ||
extract_timezone(&&d) | ||
} | ||
Value::Array(_, data) => { | ||
if let Some(v) = data.first() { | ||
extract_timezone(v) | ||
} else { | ||
Tz::Zulu | ||
} | ||
} | ||
_ => Tz::Zulu | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use chrono::prelude::*; | ||
use chrono_tz::Tz::{self, UTC}; | ||
|
||
use crate::{row, types::{Decimal, SqlType}}; | ||
|
||
use super::*; | ||
|
||
#[test] | ||
fn test_push_row() { | ||
let date_value: Date<Tz> = UTC.ymd(2016, 10, 22); | ||
let date_time_value: DateTime<Tz> = UTC.ymd(2014, 7, 8).and_hms(14, 0, 0); | ||
|
||
let decimal = Decimal::of(2.0_f64, 4); | ||
|
||
let mut block = Block::new(); | ||
block.push(row!{ | ||
i8_field: 1_i8, | ||
i16_field: 1_i16, | ||
i32_field: 1_i32, | ||
i64_field: 1_i64, | ||
|
||
u8_field: 1_u8, | ||
u16_field: 1_u16, | ||
u32_field: 1_u32, | ||
u64_field: 1_u64, | ||
|
||
f32_field: 4.66_f32, | ||
f64_field: 2.71_f64, | ||
|
||
str_field: "text", | ||
opt_filed: Some("text"), | ||
nil_filed: Option::<&str>::None, | ||
|
||
date_field: date_value, | ||
date_time_field: date_time_value, | ||
|
||
decimal_field: decimal | ||
}).unwrap(); | ||
|
||
assert_eq!(block.row_count(), 1); | ||
|
||
assert_eq!(block.columns[0].sql_type(), SqlType::Int8); | ||
assert_eq!(block.columns[1].sql_type(), SqlType::Int16); | ||
assert_eq!(block.columns[2].sql_type(), SqlType::Int32); | ||
assert_eq!(block.columns[3].sql_type(), SqlType::Int64); | ||
|
||
assert_eq!(block.columns[4].sql_type(), SqlType::UInt8); | ||
assert_eq!(block.columns[5].sql_type(), SqlType::UInt16); | ||
assert_eq!(block.columns[6].sql_type(), SqlType::UInt32); | ||
assert_eq!(block.columns[7].sql_type(), SqlType::UInt64); | ||
|
||
assert_eq!(block.columns[8].sql_type(), SqlType::Float32); | ||
assert_eq!(block.columns[9].sql_type(), SqlType::Float64); | ||
|
||
assert_eq!(block.columns[10].sql_type(), SqlType::String); | ||
assert_eq!(block.columns[11].sql_type(), SqlType::Nullable(SqlType::String.into())); | ||
assert_eq!(block.columns[12].sql_type(), SqlType::Nullable(SqlType::String.into())); | ||
|
||
assert_eq!(block.columns[13].sql_type(), SqlType::Date); | ||
assert_eq!(block.columns[14].sql_type(), SqlType::DateTime); | ||
assert_eq!(block.columns[15].sql_type(), SqlType::Decimal(18, 4)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.