示例#1
0
    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"),
            ],
        )
示例#2
0
    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"),
            ],
        )
示例#3
0
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