Skip to content

Commit

Permalink
Merge pull request #188 from Qrlew/impl_cast
Browse files Browse the repository at this point in the history
implement cast
  • Loading branch information
ngrislain authored Nov 20, 2023
2 parents 71db569 + 2174fbe commit 9b0ea7c
Show file tree
Hide file tree
Showing 8 changed files with 515 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]
## Added
- `CAST` function [MR188](https://github.com/Qrlew/qrlew/pull/188)

## [0.5.1] - 2023-11-19
## Added
Expand Down
140 changes: 138 additions & 2 deletions src/data_type/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1155,10 +1155,75 @@ Conversion function

/// Builds the cast operator
pub fn cast(into: DataType) -> impl Function {
// TODO Only cast as text is working for now
match into {
DataType::Text(t) if t == data_type::Text::full() => {
Pointwise::univariate(DataType::Any, DataType::text(), |v| v.to_string().into())
Pointwise::univariate(
//DataType::Any,
DataType::Any,
DataType::text(),
|v| v.to_string().into())
}
DataType::Float(f) if f == data_type::Float::full() => {
Pointwise::univariate(
DataType::text(),
DataType::float(),
|v| v.to_string().parse::<f64>().unwrap().into()
)
}
DataType::Integer(i) if i == data_type::Integer::full() => {
Pointwise::univariate(
DataType::text(),
DataType::integer(),
|v| v.to_string().parse::<i64>().unwrap().into()
)
}
DataType::Boolean(b) if b == data_type::Boolean::full() => {
Pointwise::univariate(
DataType::text(),
DataType::boolean(),
|v| {
let true_list = vec![
"t".to_string(), "tr".to_string(), "tru".to_string(), "true".to_string(),
"y".to_string(), "ye".to_string(), "yes".to_string(),
"on".to_string(),
"1".to_string()
];
let false_list = vec![
"f".to_string(), "fa".to_string(), "fal".to_string(), "fals".to_string(), "false".to_string(),
"n".to_string(), "no".to_string(),
"off".to_string(),
"0".to_string()
];
if true_list.contains(&v.to_string().to_lowercase()) {
true.into()
} else if false_list.contains(&v.to_string().to_lowercase()) {
false.into()
} else {
panic!()
}
}
)
}
DataType::Date(d) if d == data_type::Date::full() => {
Pointwise::univariate(
DataType::text(),
DataType::date(),
|v| todo!()
)
}
DataType::DateTime(d) if d == data_type::DateTime::full() => {
Pointwise::univariate(
DataType::text(),
DataType::date_time(),
|v| todo!()
)
}
DataType::Time(t) if t == data_type::Time::full() => {
Pointwise::univariate(
DataType::text(),
DataType::time(),
|v| todo!()
)
}
_ => todo!(),
}
Expand Down Expand Up @@ -1978,6 +2043,7 @@ mod tests {
super::{value::Value, Struct},
*,
};
use chrono;

#[test]
fn test_argument_conversion() {
Expand Down Expand Up @@ -3293,4 +3359,74 @@ mod tests {
])
);
}

#[test]
fn test_cast_as_text() {
println!("Test cast as text");
let fun = cast(DataType::text());
println!("type = {}", fun);
println!("domain = {}", fun.domain());
println!("co_domain = {}", fun.co_domain());
println!("data_type = {}", fun.data_type());

let set = DataType::integer_values([1, 3, 4]);
let im = fun.super_image(&set).unwrap();
println!("im({}) = {}", set, im);
assert!(im == DataType::text_values(["1".to_string(), "3".to_string(), "4".to_string()]));

let set = DataType::integer_values([1, 3, 4]);
let im = fun.super_image(&set).unwrap();
println!("im({}) = {}", set, im);
assert!(im == DataType::text_values(["1".to_string(), "3".to_string(), "4".to_string()]));

let set = DataType::date_value(chrono::NaiveDate::from_ymd_opt(2015, 6, 3).unwrap());
let im = fun.super_image(&set).unwrap();
println!("im({}) = {}", set, im);
assert!(im == DataType::text_values(["2015-06-03".to_string()]));
}

#[test]
fn test_cast_as_float() {
println!("Test cast as float");
let fun = cast(DataType::float());
println!("type = {}", fun);
println!("domain = {}", fun.domain());
println!("co_domain = {}", fun.co_domain());
println!("data_type = {}", fun.data_type());

let set = DataType::text_values(["1.5".to_string(), "3".to_string(), "4.555".to_string()]);
let im = fun.super_image(&set).unwrap();
println!("im({}) = {}", set, im);
assert!(im == DataType::float_values([1.5, 3., 4.555]));
}

#[test]
fn test_cast_as_integer() {
println!("\nTest cast as integer");
let fun = cast(DataType::integer());
println!("type = {}", fun);
println!("domain = {}", fun.domain());
println!("co_domain = {}", fun.co_domain());
println!("data_type = {}", fun.data_type());

let set = DataType::text_values(["1".to_string(), "3".to_string(), "4".to_string()]);
let im = fun.super_image(&set).unwrap();
println!("im({}) = {}", set, im);
assert!(im == DataType::integer_values([1, 3, 4]));
}

#[test]
fn test_cast_to_boolean() {
println!("\nTest cast as boolean");
let fun = cast(DataType::boolean());
println!("type = {}", fun);
println!("domain = {}", fun.domain());
println!("co_domain = {}", fun.co_domain());
println!("data_type = {}", fun.data_type());

let set = DataType::text_values(["1".to_string(), "tru".to_string()]);
let im = fun.super_image(&set).unwrap();
println!("im({}) = {}", set, im);
assert!(im == DataType::boolean_value(true));
}
}
16 changes: 14 additions & 2 deletions src/expr/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,16 @@ pub enum Function {
CastAsText,
CastAsFloat,
CastAsInteger,
CastAsBoolean,
CastAsDateTime,
CastAsDate,
CastAsTime,
Least,
Greatest,
Rtrim,
Ltrim,
Substr,
SubstrWithSize,
SubstrWithSize
}

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
Expand Down Expand Up @@ -119,7 +122,10 @@ impl Function {
| Function::CastAsText
| Function::CastAsFloat
| Function::CastAsInteger
| Function::CastAsBoolean
| Function::CastAsDateTime
| Function::CastAsDate
| Function::CastAsTime
// Binary Functions
| Function::Pow
| Function::Position
Expand Down Expand Up @@ -179,7 +185,10 @@ impl Function {
| Function::CastAsText
| Function::CastAsFloat
| Function::CastAsInteger
| Function::CastAsDateTime => Arity::Unary,
| Function::CastAsBoolean
| Function::CastAsDateTime
| Function::CastAsDate
| Function::CastAsTime => Arity::Unary,
// Binary Function
Function::Pow
| Function::Position
Expand Down Expand Up @@ -260,7 +269,10 @@ impl fmt::Display for Function {
Function::CastAsText => "cast_as_text",
Function::CastAsInteger => "cast_as_integer",
Function::CastAsFloat => "cast_as_float",
Function::CastAsBoolean => "cast_as_boolean",
Function::CastAsDateTime => "cast_as_date_time",
Function::CastAsDate => "cast_as_date",
Function::CastAsTime => "cast_as_time",
// Binary Functions
Function::Pow => "pow",
Function::Position => "position",
Expand Down
9 changes: 6 additions & 3 deletions src/expr/implementation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,12 @@ function_implementations!(
{
match x {
Function::CastAsText => Arc::new(function::cast(DataType::text())),
Function::CastAsInteger => Arc::new(function::cast(DataType::integer())),
Function::CastAsFloat => Arc::new(function::cast(DataType::float())),
Function::CastAsDateTime => Arc::new(function::cast(DataType::date_time())),
Function::CastAsInteger => Arc::new(Optional::new(function::cast(DataType::integer()))),
Function::CastAsFloat => Arc::new(Optional::new(function::cast(DataType::float()))),
Function::CastAsBoolean => Arc::new(Optional::new(function::cast(DataType::boolean()))),
Function::CastAsDateTime => Arc::new(Optional::new(function::cast(DataType::date_time()))),
Function::CastAsDate => Arc::new(Optional::new(function::cast(DataType::date()))),
Function::CastAsTime => Arc::new(Optional::new(function::cast(DataType::time()))),
Function::Concat(n) => Arc::new(function::concat(n)),
Function::Random(n) => Arc::new(function::random(Mutex::new(OsRng))), //TODO change this initialization
Function::Coalesce => Arc::new(function::coalesce()),
Expand Down
134 changes: 133 additions & 1 deletion src/expr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,10 @@ impl_unary_function_constructors!(
CastAsText,
CastAsInteger,
CastAsFloat,
CastAsDateTime
CastAsBoolean,
CastAsDateTime,
CastAsDate,
CastAsTime
); // TODO Complete that

/// Implement binary function constructors
Expand Down Expand Up @@ -2862,4 +2865,133 @@ mod tests {
DataType::optional(DataType::text())
);
}

#[test]
fn test_cast_integer_text() {
println!("integer => text");
let expression = Expr::cast_as_text(
Expr::col("col1".to_string())
);
println!("expression = {}", expression);
println!("expression domain = {}", expression.domain());
println!("expression co domain = {}", expression.co_domain());
println!("expression data type = {}", expression.data_type());
let set = DataType::structured([
("col1", DataType::integer_values([1, 2, 3])),
]);
println!(
"expression super image = {}",
expression.super_image(&set).unwrap()
);
assert_eq!(
expression.super_image(&set).unwrap(),
DataType::text_values(["1".to_string(), "2".to_string(), "3".to_string()])
);

println!("\ntext => integer");
let expression = Expr::cast_as_integer(
Expr::col("col1".to_string())
);
println!("expression = {}", expression);
println!("expression domain = {}", expression.domain());
println!("expression co domain = {}", expression.co_domain());
println!("expression data type = {}", expression.data_type());
let set = DataType::structured([
("col1", DataType::text_values(["1".to_string(), "2".to_string(), "3".to_string()])),
]);
println!(
"expression super image = {}",
expression.super_image(&set).unwrap()
);
assert_eq!(
expression.super_image(&set).unwrap(),
DataType::integer_values([1, 2, 3])
);
}

#[test]
fn test_cast_float_text() {
println!("float => text");
let expression = Expr::cast_as_text(
Expr::col("col1".to_string())
);
println!("expression = {}", expression);
println!("expression domain = {}", expression.domain());
println!("expression co domain = {}", expression.co_domain());
println!("expression data type = {}", expression.data_type());
let set = DataType::structured([
("col1", DataType::float_values([1.1, 2., 3.5])),
]);
println!(
"expression super image = {}",
expression.super_image(&set).unwrap()
);
assert_eq!(
expression.super_image(&set).unwrap(),
DataType::text_values(["1.1".to_string(), "2".to_string(), "3.5".to_string()])
);

println!("\ntext => float");
let expression = Expr::cast_as_float(
Expr::col("col1".to_string())
);
println!("expression = {}", expression);
println!("expression domain = {}", expression.domain());
println!("expression co domain = {}", expression.co_domain());
println!("expression data type = {}", expression.data_type());
let set = DataType::structured([
("col1", DataType::text_values(["1.1".to_string(), "2".to_string(), "3.5".to_string()])),
]);
println!(
"expression super image = {}",
expression.super_image(&set).unwrap()
);
assert_eq!(
expression.super_image(&set).unwrap(),
DataType::float_values([1.1, 2., 3.5])
);
}

#[test]
fn test_cast_boolean_text() {
println!("boolean => text");
let expression = Expr::cast_as_text(
Expr::col("col1".to_string())
);
println!("expression = {}", expression);
println!("expression domain = {}", expression.domain());
println!("expression co domain = {}", expression.co_domain());
println!("expression data type = {}", expression.data_type());
let set = DataType::structured([
("col1", DataType::boolean_values([true, false])),
]);
println!(
"expression super image = {}",
expression.super_image(&set).unwrap()
);
assert_eq!(
expression.super_image(&set).unwrap(),
DataType::text_values(["true".to_string(), "false".to_string()])
);

println!("\ntext => boolean");
let expression = Expr::cast_as_boolean(
Expr::col("col1".to_string())
);
println!("expression = {}", expression);
println!("expression domain = {}", expression.domain());
println!("expression co domain = {}", expression.co_domain());
println!("expression data type = {}", expression.data_type());
let set = DataType::structured([
("col1", DataType::text_values(["n".to_string(), "fa".to_string(), "off".to_string()])),
]);
println!(
"expression super image = {}",
expression.super_image(&set).unwrap()
);
assert_eq!(
expression.super_image(&set).unwrap(),
DataType::boolean_value(false)
);
}
}
Loading

0 comments on commit 9b0ea7c

Please sign in to comment.