Пример #1
0
def preprocess_and(
    expression: Expression, variables: TGroupedExpressions
) -> Expression:
    new_expression = []

    for expression in expression.args:
        maybe_expr = preprocess_expression(expression, variables)
        if maybe_expr:
            new_expression.append(maybe_expr)

    return Expression("And", new_expression)
Пример #2
0
def reflect_expr(expr: Expression):
    assert expr.operator in COMPARISONS
    reflections = {
        "Gt": "Lt",
        "Geq": "Leq",
        "Lt": "Gt",
        "Leq": "Geq",
    }
    left, right = expr.args
    op = expr.operator
    return Expression(reflections.get(op, op), [right, left])
Пример #3
0
def sub_var(variable: Variable, value, expression: Expression) -> Expression:
    """Substitute ``value`` for ``variable`` in ``expression``."""
    new_expr = []
    for arg in expression.args:
        if isinstance(arg, Expression):
            arg = sub_var(variable, value, arg)
        elif arg == variable:
            arg = value

        new_expr.append(arg)

    return Expression(expression.operator, new_expr)
Пример #4
0
def preprocess(expression: Expression) -> Expression:
    # Collect expressions that constrain variables besides _this.
    variables: TGroupedExpressions = defaultdict(list)
    new_expr = preprocess_expression(expression, variables)
    assert new_expr is not None

    # Join each expression by AND.
    expressions = {var: Expression("And", args) for var, args in variables.items()}

    # Subsitute _this for each variable.
    expressions = {
        var: sub_this(var, expression) for var, expression in expressions.items()
    }

    # Subsitute new expressions for variables in original expression.
    for var, expr in expressions.items():
        new_expr = sub_var(var, expr, preprocess(new_expr))

    return new_expr
Пример #5
0
def translate_compare(expression: Expression, session: Session, model,
                      get_model):
    (left, right) = expression.args
    left_path = dot_path(left)
    right_path = dot_path(right)

    if left_path[1:]:
        assert left_path[0] == Variable("_this")
        assert not right_path
        path, field_name = left_path[1:-1], left_path[-1]
        return translate_dot(
            path,
            session,
            model,
            functools.partial(emit_compare, field_name, right,
                              expression.operator),
        )
    elif right_path and right_path[0] == "_this":
        return translate_compare(
            Expression(flip_op(expression.operator), [right, left]),
            session,
            model,
            get_model,
        )
    else:
        assert left == Variable("_this")
        if not isinstance(right, model):
            return sql.false()

        if expression.operator not in ("Eq", "Unify"):
            raise UnsupportedError(
                f"Unsupported comparison: {expression}. Models can only be compared"
                " with `=` or `==`")

        primary_keys = [pk.name for pk in inspect(model).primary_key]
        pk_filter = sql.true()
        for key in primary_keys:
            pk_filter &= getattr(model, key) == getattr(right, key)
        return pk_filter
Пример #6
0
def translate_in(expression, session, model, get_model):
    assert expression.operator == "In"
    left = expression.args[0]
    right = expression.args[1]

    # IN means at least something must be contained in the property.

    # There are two possible types of in operations. In both, the right hand side
    # should be a dot op.

    path = dot_path(right)
    assert path[0] == "_this"
    path = path[1:]
    assert path

    # Partial In: LHS is an expression
    if isinstance(left, Expression):
        return translate_dot(
            path,
            session,
            model,
            functools.partial(emit_subexpression, left, get_model),
        )
    elif isinstance(left, Variable):
        # A variable with no additional constraints
        return translate_dot(
            path,
            session,
            model,
            functools.partial(emit_subexpression, Expression("And", []),
                              get_model),
        )
    else:
        # Contains: LHS is not an expression.
        # TODO (dhatch) Missing check, left type must match type of the target?
        path, field_name = path[:-1], path[-1]
        return translate_dot(
            path, session, model,
            functools.partial(emit_contains, field_name, left))
Пример #7
0
def test_preprocess_nested_many_many():
    _this = Variable("_this")
    expression = Expression(
        "And",
        [
            Expression("Isa", [_this, Pattern("Post", {})]),
            Expression(
                "In",
                [Variable("_tag_16"),
                 Expression("Dot", [_this, "tags"])]),
            Expression(
                "In",
                [
                    Variable("_user_18"),
                    Expression("Dot", [Variable("_tag_16"), "users"]),
                ],
            ),
            Expression(
                "Unify",
                [
                    "admin",
                    Expression("Dot", [Variable("_user_18"), "username"])
                ],
            ),
        ],
    )

    vars = defaultdict(list)
    new_expression = preprocess_expression(expression, vars)

    assert new_expression == Expression(
        "And",
        [
            Expression("Isa", [_this, Pattern("Post", {})]),
            Expression(
                "In",
                [Variable("_tag_16"),
                 Expression("Dot", [_this, "tags"])]),
        ],
    )

    assert vars == {
        Variable("_tag_16"): [
            Expression(
                "In",
                [
                    Variable("_user_18"),
                    Expression("Dot", [Variable("_tag_16"), "users"]),
                ],
            )
        ],
        Variable("_user_18"): [
            Expression(
                "Unify",
                [
                    "admin",
                    Expression("Dot", [Variable("_user_18"), "username"])
                ],
            )
        ],
    }

    users_expr = Expression("And", [
        Expression("Unify",
                   ["admin", Expression("Dot", [_this, "username"])])
    ])
    tags_expr = Expression(
        "And",
        [Expression(
            "In", [users_expr, Expression("Dot", [_this, "users"])])])

    assert preprocess(expression) == Expression(
        "And",
        [
            Expression("Isa", [_this, Pattern("Post", {})]),
            Expression("In", [tags_expr,
                              Expression("Dot", [_this, "tags"])]),
        ],
    )