def test_clean_condition_timestamp_wrong_value(self): with self.assertRaises(PromptingError) as cm: self._call_clean_value( ParamSchema.Condition(), { "operation": "timestamp_is_greater_than", "column": "A", "value": "Yesterday", "isCaseSensitive": False, "isRegex": False, }, input_table_columns=[TIMESTAMP("A")], ) self.assertEqual( cm.exception.errors, [ PromptingError.CannotCoerceValueToTimestamp("Yesterday"), ], )
def test_clean_condition_timestamp_wrong_column_type_and_wrong_value(self): with self.assertRaises(PromptingError) as cm: self._call_clean_value( ParamSchema.Condition(), { "operation": "timestamp_is_greater_than", "column": "A", "value": "Yesterday", "isCaseSensitive": False, "isRegex": False, }, input_table_columns=[NUMBER("A")], ) self.assertEqual( cm.exception.errors, [ PromptingError.WrongColumnType( ["A"], "number", frozenset({"date", "timestamp"})), PromptingError.CannotCoerceValueToTimestamp("Yesterday"), ], )
def _clean_condition_recursively( value: Dict[str, Any], column_types: Dict[str, str] ) -> Tuple[Optional[Dict[str, Any]], List[PromptingError]]: if value["operation"] == "": return None, [] elif value["operation"] in {"and", "or"}: errors = [] conditions = [] for entry in value["conditions"]: clean_condition, clean_errors = _clean_condition_recursively( entry, column_types) errors.extend(clean_errors) if clean_condition is not None: conditions.append(clean_condition) if len(conditions) == 0: return None, errors elif len(conditions) == 1: return conditions[0], errors else: return { "operation": value["operation"], "conditions": conditions, }, errors elif value["operation"] in _InverseOperations: clean_condition, errors = _clean_condition_recursively( { **value, "operation": _InverseOperations[value["operation"]] }, column_types, ) if clean_condition is None: return None, errors else: return {"operation": "not", "condition": clean_condition}, errors else: clean_condition = None errors = [] if value["column"] not in column_types: # No valid column selected. # # It would be nice to warn on invalid column ... but [2020-11-16] # we don't have a way to do that, because the default params are # empty and we validate them. More-general problem of the # same flavor: https://www.pivotaltracker.com/story/show/174473146 pass else: column_type = column_types[value["column"]] if value["operation"].startswith("text"): if column_type != "text": errors.append( PromptingError.WrongColumnType([value["column"]], None, frozenset(["text"]))) else: clean_condition = value elif value["operation"].startswith("number"): if column_type != "number": errors.append( PromptingError.WrongColumnType([value["column"]], column_type, frozenset(["number"]))) try: number_value = float(value["value"]) except ValueError: errors.append( PromptingError.CannotCoerceValueToNumber( value["value"])) if not errors: clean_condition = { "operation": value["operation"], "column": value["column"], "value": number_value, } elif value["operation"].startswith("timestamp"): if column_type not in {"date", "timestamp"}: errors.append( PromptingError.WrongColumnType( [value["column"]], column_type, frozenset(["date", "timestamp"]), )) try: _validate_iso8601_string(value["value"]) except ValueError: errors.append( PromptingError.CannotCoerceValueToTimestamp( value["value"])) if not errors: clean_condition = { "operation": value["operation"], "column": value["column"], "value": value["value"], } else: assert value["operation"].startswith("cell") clean_condition = { "operation": value["operation"], "column": value["column"], } return clean_condition, errors