Skip to content

Commit

Permalink
try to auto convert types for operators where incorrect types were su…
Browse files Browse the repository at this point in the history
…pplied for the filter value for the column type
  • Loading branch information
kingsleyh committed Aug 18, 2024
1 parent 472b9a2 commit 8ed7b52
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
60 changes: 60 additions & 0 deletions src/lib/filtering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,15 @@ impl Filtering {
FilterOperator::GreaterThan => match filter_column {
FilterColumn::Int(c, v) => Ok(Filtering::sql_str(c, ">", v.to_string())),
FilterColumn::Float(c, v) => Ok(Filtering::sql_str(c, ">", v.to_string())),

// try to convert the value to a valid type for the operator
FilterColumn::String(c, v) => {
let v = v.replace("'","").parse::<f64>().ok().ok_or_else(|| {
eyre::eyre!( "GreaterThan does not support String and auto conversion to Float failed with value: '{}' for column: '{}'",v,c)
})?;
Ok(Filtering::sql_str(c, ">", v.to_string()))
}

_ => Err(eyre::eyre!(
"Invalid column type '{}' for filter operator GreaterThan",
filter_column.to_string()
Expand All @@ -491,6 +500,15 @@ impl Filtering {
FilterOperator::GreaterThanOrEqual => match filter_column {
FilterColumn::Int(c, v) => Ok(Filtering::sql_str(c, ">=", v.to_string())),
FilterColumn::Float(c, v) => Ok(Filtering::sql_str(c, ">=", v.to_string())),

// try to convert the value to a valid type for the operator
FilterColumn::String(c, v) => {
let v = v.replace("'","").parse::<f64>().ok().ok_or_else(|| {
eyre::eyre!( "GreaterThanOrEqual does not support String and auto conversion to Float failed with value: '{}' for column: '{}'",v,c)
})?;
Ok(Filtering::sql_str(c, ">=", v.to_string()))
}

_ => Err(eyre::eyre!(
"Invalid column type '{}' for filter operator GreaterThanOrEqual",
filter_column.to_string()
Expand All @@ -499,6 +517,15 @@ impl Filtering {
FilterOperator::LessThan => match filter_column {
FilterColumn::Int(c, v) => Ok(Filtering::sql_str(c, "<", v.to_string())),
FilterColumn::Float(c, v) => Ok(Filtering::sql_str(c, "<", v.to_string())),

// try to convert the value to a valid type for the operator
FilterColumn::String(c, v) => {
let v = v.replace("'","").parse::<f64>().ok().ok_or_else(|| {
eyre::eyre!( "LessThan does not support String and auto conversion to Float failed with value: '{}' for column: '{}'",v,c)
})?;
Ok(Filtering::sql_str(c, "<", v.to_string()))
}

_ => Err(eyre::eyre!(
"Invalid column type '{}' for filter operator LessThan",
filter_column.to_string()
Expand All @@ -507,20 +534,41 @@ impl Filtering {
FilterOperator::LessThanOrEqual => match filter_column {
FilterColumn::Int(c, v) => Ok(Filtering::sql_str(c, "<=", v.to_string())),
FilterColumn::Float(c, v) => Ok(Filtering::sql_str(c, "<=", v.to_string())),

// try to convert the value to a valid type for the operator
FilterColumn::String(c, v) => {
let v = v.replace("'","").parse::<f64>().ok().ok_or_else(|| {
eyre::eyre!( "LessThanOrEqual does not support String and auto conversion to Float failed with value: '{}' for column: '{}'",v,c)
})?;
Ok(Filtering::sql_str(c, "<=", v.to_string()))
}

_ => Err(eyre::eyre!(
"Invalid column type '{}' for filter operator LessThanOrEqual",
filter_column.to_string()
)),
},
FilterOperator::Like => match filter_column {
FilterColumn::String(c, v) => Ok(Filtering::sql_str_i(cs, c, "LIKE", v)),

// try to convert the value to a valid type for the operator
FilterColumn::Int(c, v) => Ok(Filtering::sql_str_i(cs, c, "LIKE", format!("'%{}%'", v.to_string()))),
FilterColumn::Float(c, v) => Ok(Filtering::sql_str_i(cs , c, "LIKE", format!("'%{}%'", v.to_string()))),
FilterColumn::Bool(c, v) => Ok(Filtering::sql_str_i(cs, c, "LIKE", format!("'%{}%'", v.to_string()))),

_ => Err(eyre::eyre!(
"Invalid column type '{}' for filter operator Like",
filter_column.to_string()
)),
},
FilterOperator::NotLike => match filter_column {
FilterColumn::String(c, v) => Ok(Filtering::sql_str_i(cs, c, "NOT LIKE", v)),

// try to convert the value to a valid type for the operator
FilterColumn::Int(c, v) => Ok(Filtering::sql_str_i(cs, c, "NOT LIKE", format!("'%{}%'", v.to_string()))),
FilterColumn::Float(c, v) => Ok(Filtering::sql_str_i(cs, c, "NOT LIKE", format!("'%{}%'", v.to_string()))),
FilterColumn::Bool(c, v) => Ok(Filtering::sql_str_i(cs, c, "NOT LIKE", format!("'%{}%'", v.to_string()))),

_ => Err(eyre::eyre!(
"Invalid column type '{}' for filter operator NotLike",
filter_column.to_string()
Expand Down Expand Up @@ -568,13 +616,25 @@ impl Filtering {
},
FilterOperator::StartsWith => match filter_column {
FilterColumn::String(c, v) => Ok(Filtering::sql_str_i(cs, c, "LIKE", v)),

// try to convert the value to a valid type for the operator
FilterColumn::Int(c, v) => Ok(Filtering::sql_str_i(cs, c, "LIKE", format!("'{}%'", v.to_string()))),
FilterColumn::Float(c, v) => Ok(Filtering::sql_str_i(cs, c, "LIKE", format!("'{}%'", v.to_string()))),
FilterColumn::Bool(c, v) => Ok(Filtering::sql_str_i(cs, c, "LIKE", format!("'{}%'", v.to_string()))),

_ => Err(eyre::eyre!(
"Invalid column type '{}' for filter operator Like",
filter_column.to_string()
)),
},
FilterOperator::EndsWith => match filter_column {
FilterColumn::String(c, v) => Ok(Filtering::sql_str_i(cs, c, "LIKE", v)),

// try to convert the value to a valid type for the operator
FilterColumn::Int(c, v) => Ok(Filtering::sql_str_i(cs, c, "LIKE", format!("'%{}'", v.to_string()))),
FilterColumn::Float(c, v) => Ok(Filtering::sql_str_i(cs, c, "LIKE", format!("'%{}'", v.to_string()))),
FilterColumn::Bool(c, v) => Ok(Filtering::sql_str_i(cs, c, "LIKE", format!("'%{}'", v.to_string()))),

_ => Err(eyre::eyre!(
"Invalid column type '{}' for filter operator Like",
filter_column.to_string()
Expand Down
64 changes: 64 additions & 0 deletions tests/unit/filtering_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,70 @@ fn test_filtering_with_multiple_rules_and_different_operators_and_values_swapped
);
}

#[test]
fn test_filtering_auto_conversions_when_wrong_type_passed() {
let filtering = Filtering::new(
&[
Ok(FilteringRule {
filter_column: FilterColumn::String("age", "'18'".to_string()),
filter_operator: FilterOperator::GreaterThan,
conditional_operator: ConditionalOperator::And,
}),
Ok(FilteringRule {
filter_column: FilterColumn::String("height", "'20.3'".to_string()),
filter_operator: FilterOperator::GreaterThanOrEqual,
conditional_operator: ConditionalOperator::And,
}),
Ok(FilteringRule {
filter_column: FilterColumn::String("age", "'18'".to_string()),
filter_operator: FilterOperator::LessThan,
conditional_operator: ConditionalOperator::And,
}),
Ok(FilteringRule {
filter_column: FilterColumn::String("age", "'0.2'".to_string()),
filter_operator: FilterOperator::LessThanOrEqual,
conditional_operator: ConditionalOperator::And,
}),
Ok(FilteringRule {
filter_column: FilterColumn::Int("code", 12),
filter_operator: FilterOperator::Like,
conditional_operator: ConditionalOperator::Or,
}),
Ok(FilteringRule {
filter_column: FilterColumn::Float("count", 10.4),
filter_operator: FilterOperator::Like,
conditional_operator: ConditionalOperator::Or,
}),
Ok(FilteringRule {
filter_column: FilterColumn::Bool("shipped", true),
filter_operator: FilterOperator::Like,
conditional_operator: ConditionalOperator::Or,
}),
Ok(FilteringRule {
filter_column: FilterColumn::Int("code2", 12),
filter_operator: FilterOperator::NotLike,
conditional_operator: ConditionalOperator::Or,
}),
Ok(FilteringRule {
filter_column: FilterColumn::Float("count2", 10.4),
filter_operator: FilterOperator::NotLike,
conditional_operator: ConditionalOperator::Or,
}),
Ok(FilteringRule {
filter_column: FilterColumn::Bool("shipped2", true),
filter_operator: FilterOperator::NotLike,
conditional_operator: ConditionalOperator::Or,
}),
],
true,
);
assert_eq!(filtering.filters.len(), 10);
assert_eq!(
filtering.sql,
" WHERE age > 18 AND height >= 20.3 AND age < 18 AND age <= 0.2 OR LOWER(code) LIKE LOWER('%12%') OR LOWER(count) LIKE LOWER('%10.4%') OR LOWER(shipped) LIKE LOWER('%true%') OR LOWER(code2) NOT LIKE LOWER('%12%') OR LOWER(count2) NOT LIKE LOWER('%10.4%') OR LOWER(shipped2) NOT LIKE LOWER('%true%')"
);
}

#[test]
fn test_filtering_with_multiple_rules_and_different_operators_and_values_swapped_and_mixed_and_repeated(
) {
Expand Down

0 comments on commit 8ed7b52

Please sign in to comment.