-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: fixed condition parsing and display
- Loading branch information
1 parent
d5c001c
commit 519da2c
Showing
5 changed files
with
145 additions
and
143 deletions.
There are no files selected for viewing
16 changes: 8 additions & 8 deletions
16
crates/frontend/src/components/condition_pills/condition_pills.rs
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 |
---|---|---|
@@ -1,6 +1,122 @@ | ||
use std::fmt::Display; | ||
|
||
use serde_json::{Map, Value}; | ||
|
||
#[derive(Debug, Clone)] | ||
pub enum ConditionOperator { | ||
Is, | ||
In, | ||
Has, | ||
Between, | ||
Other(String), | ||
} | ||
|
||
impl Display for ConditionOperator { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
match self { | ||
Self::Has => f.write_str("has"), | ||
Self::Is => f.write_str("is"), | ||
Self::In => f.write_str("in"), | ||
Self::Between => f.write_str("between"), | ||
Self::Other(o) => f.write_str(o), | ||
} | ||
} | ||
} | ||
|
||
impl From<(String, &Vec<Value>)> for ConditionOperator { | ||
fn from(value: (String, &Vec<Value>)) -> Self { | ||
let (operator, operands) = value; | ||
let operand_0 = operands.get(0); | ||
let operand_1 = operands.get(1); | ||
let operand_2 = operands.get(2); | ||
match (operator.as_str(), operand_0, operand_1, operand_2) { | ||
// assuming there will be only two operands, one with the dimension name and other with the value | ||
("==", _, _, None) => ConditionOperator::Is, | ||
("<=", Some(_), Some(Value::Object(a)), Some(_)) if a.contains_key("var") => { | ||
ConditionOperator::Between | ||
} | ||
// assuming there will be only two operands, one with the dimension name and other with the value | ||
("in", Some(Value::Object(a)), Some(_), None) if a.contains_key("var") => { | ||
ConditionOperator::In | ||
} | ||
// assuming there will be only two operands, one with the dimension name and other with the value | ||
("in", Some(_), Some(Value::Object(a)), None) if a.contains_key("var") => { | ||
ConditionOperator::Has | ||
} | ||
_ => ConditionOperator::Other(operator), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Clone)] | ||
pub struct Condition { | ||
pub left_operand: String, | ||
pub operator: String, | ||
pub operator: ConditionOperator, | ||
pub right_operand: String, | ||
} | ||
|
||
impl TryFrom<&Map<String, Value>> for Condition { | ||
type Error = &'static str; | ||
fn try_from(source: &Map<String, Value>) -> Result<Self, Self::Error> { | ||
if let Some(operator) = source.keys().next() { | ||
let emty_vec = vec![]; | ||
let operands = source[operator].as_array().unwrap_or(&emty_vec); | ||
|
||
let operator = ConditionOperator::from((operator.to_string(), operands)); | ||
|
||
let dimension_name = operands | ||
.iter() | ||
.find_map(|item| match item.as_object() { | ||
Some(o) if o.contains_key("var") => { | ||
Some(o["var"].as_str().unwrap_or("")) | ||
} | ||
_ => None, | ||
}) | ||
.unwrap_or(""); | ||
|
||
let other_operands = operands | ||
.iter() | ||
.filter_map(|item| { | ||
if item.is_object() && item.as_object().unwrap().contains_key("var") { | ||
return None; | ||
} | ||
|
||
match item { | ||
Value::Null => String::from("null"), | ||
Value::String(v) => v.clone(), | ||
_ => format!("{}", item), | ||
} | ||
.into() | ||
}) | ||
.collect::<Vec<String>>() | ||
.join(","); | ||
|
||
return Ok(Condition { | ||
operator, | ||
left_operand: dimension_name.to_string(), | ||
right_operand: other_operands, | ||
}); | ||
} | ||
|
||
Err("not a valid condition map") | ||
} | ||
} | ||
|
||
impl TryFrom<&Value> for Condition { | ||
type Error = &'static str; | ||
fn try_from(value: &Value) -> Result<Self, Self::Error> { | ||
let obj = value | ||
.as_object() | ||
.ok_or("not a valid condition value, should be an object")?; | ||
Condition::try_from(obj) | ||
} | ||
} | ||
|
||
impl Into<String> for Condition { | ||
fn into(self) -> String { | ||
format!( | ||
"{} {} {}", | ||
self.left_operand, self.operator, self.right_operand | ||
) | ||
} | ||
} |
147 changes: 16 additions & 131 deletions
147
crates/frontend/src/components/condition_pills/utils.rs
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,135 +1,20 @@ | ||
use std::mem::swap; | ||
|
||
use super::types::Condition; | ||
use serde_json::Value; | ||
|
||
pub fn parse_conditions(input: Vec<Condition>) -> Vec<Condition> { | ||
let mut conditions = Vec::new(); | ||
|
||
// Split the string by "&&" and iterate over each condition | ||
for condition in input { | ||
let mut key = condition.left_operand; | ||
let mut op = condition.operator; | ||
let mut val = condition.right_operand; | ||
if op == "in" { | ||
swap(&mut key, &mut val) | ||
} | ||
// Add a space after key | ||
key.push(' '); | ||
match op.as_str() { | ||
"==" => { | ||
val = val.trim_matches('"').to_string(); | ||
op = "is".to_string(); | ||
} | ||
"<=" => { | ||
val = val.trim_matches('"').to_string(); | ||
op = "BETWEEN".to_string(); | ||
} | ||
_ => { | ||
val = val.trim_matches('"').to_string(); | ||
op = "has".to_string(); | ||
} | ||
} | ||
op.push(' '); | ||
|
||
conditions.push(Condition { | ||
left_operand: key, | ||
operator: op, | ||
right_operand: val, | ||
}); | ||
} | ||
|
||
conditions | ||
} | ||
|
||
pub fn extract_and_format(condition: &Value) -> Vec<Condition> { | ||
let mut formatted_conditions = Vec::new(); | ||
if condition.is_object() && condition.get("and").is_some() { | ||
// Handling complex "and" conditions | ||
let empty_vec = vec![]; | ||
let conditions_json = condition | ||
.get("and") | ||
.and_then(|val| val.as_array()) | ||
.unwrap_or(&empty_vec); // Default to an empty vector if not an array | ||
|
||
for cond in conditions_json { | ||
if let Some(formatted_condition) = format_condition(cond) { | ||
formatted_conditions.push(formatted_condition); | ||
} | ||
} | ||
} else if let Some(formatted_condition) = format_condition(condition) { | ||
// Handling single conditions | ||
formatted_conditions.push(formatted_condition); | ||
} | ||
formatted_conditions | ||
} | ||
|
||
fn format_condition(condition: &Value) -> Option<Condition> { | ||
if let Some(ref operator) = condition.as_object().and_then(|obj| obj.keys().next()) { | ||
let empty_vec = vec![]; | ||
let operands = condition[operator].as_array().unwrap_or(&empty_vec); | ||
|
||
// Handling the "in" operator differently | ||
if operator.as_str() == "in" { | ||
let left_operand = &operands[0]; | ||
let right_operand = &operands[1]; | ||
|
||
let left_str = if left_operand.is_string() { | ||
format!("\"{}\"", left_operand.as_str().unwrap()) | ||
} else { | ||
format!("{}", left_operand) | ||
}; | ||
|
||
if right_operand.is_object() && right_operand["var"].is_string() { | ||
let var_str = right_operand["var"].as_str().unwrap(); | ||
return Some(Condition { | ||
left_operand: left_str, | ||
operator: operator.to_string(), | ||
right_operand: var_str.to_string(), | ||
}); | ||
} | ||
} | ||
|
||
// Handline the "<=" operator differently | ||
if operator.as_str() == "<=" { | ||
let left_operand = &operands[0]; | ||
let right_operand = &operands[2]; | ||
let mid_operand = &operands[1]; | ||
|
||
let left_str = format!("{}", left_operand).trim_matches('"').to_string(); | ||
let right_str = format!("{}", right_operand).trim_matches('"').to_string(); | ||
|
||
if mid_operand.is_object() && mid_operand["var"].is_string() { | ||
let var_str = mid_operand["var"].as_str().unwrap(); | ||
return Some(Condition { | ||
left_operand: var_str.to_string(), | ||
operator: operator.to_string(), | ||
right_operand: left_str + "," + &right_str, | ||
}); | ||
} | ||
} | ||
// Handling regular operators | ||
if let Some(first_operand) = operands.get(0) { | ||
if first_operand.is_object() && first_operand["var"].is_string() { | ||
let key = first_operand["var"] | ||
.as_str() | ||
.unwrap_or("UnknownVar") | ||
.to_string(); | ||
if let Some(value) = operands.get(1) { | ||
let val_str = match value { | ||
Value::Null => "null".to_string(), | ||
Value::String(v) => v.clone(), | ||
_ => value.to_string(), | ||
}; | ||
return Some(Condition { | ||
left_operand: key.to_string(), | ||
operator: operator.to_string(), | ||
right_operand: val_str, | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
|
||
None | ||
pub fn extract_conditions(context: &Value) -> Vec<Condition> { | ||
context | ||
.as_object() | ||
.and_then(|obj| { | ||
obj.get("and") | ||
.and_then(|v| v.as_array()) | ||
.and_then(|arr| { | ||
Some( | ||
arr.iter() | ||
.filter_map(|condition| Condition::try_from(condition).ok()) | ||
.collect::<Vec<Condition>>(), | ||
) | ||
}) | ||
.or_else(|| Condition::try_from(obj).ok().and_then(|v| Some(vec![v]))) | ||
}) | ||
.unwrap_or_default() | ||
} |
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