summaryrefslogtreecommitdiff
path: root/test/sql/test_operators.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/sql/test_operators.py')
-rw-r--r--test/sql/test_operators.py193
1 files changed, 189 insertions, 4 deletions
diff --git a/test/sql/test_operators.py b/test/sql/test_operators.py
index e5176713a..88d1ea053 100644
--- a/test/sql/test_operators.py
+++ b/test/sql/test_operators.py
@@ -165,6 +165,21 @@ class DefaultColumnComparatorTest(
loop = LoopOperate()
is_(operator(loop, *arg), operator)
+ @testing.combinations(
+ operators.add,
+ operators.and_,
+ operators.or_,
+ operators.mul,
+ argnames="op",
+ )
+ def test_nonsensical_negations(self, op):
+
+ opstring = compiler.OPERATORS[op]
+ self.assert_compile(
+ select(~op(column("x"), column("q"))),
+ f"SELECT NOT (x{opstring}q) AS anon_1",
+ )
+
def test_null_true_false_is_sanity_checks(self):
d = default.DefaultDialect()
@@ -328,6 +343,176 @@ class DefaultColumnComparatorTest(
)
+class MultiElementExprTest(fixtures.TestBase, testing.AssertsCompiledSQL):
+ __dialect__ = "default"
+
+ @testing.combinations(True, False, argnames="reverse")
+ @testing.combinations(True, False, argnames="negate")
+ def test_associatives_mismatched_type(self, reverse, negate):
+ """test we get two separate exprs if the types dont match, operator
+ is not lost.
+
+ the expressions here don't generally make sense from a SQL
+ perspective, we are checking just that the operators / parenthesis /
+ negation works out in the SQL string to reasonably correspond to
+ what the Python structures look like.
+
+ """
+
+ expr1 = column("i1", Integer) + column("i2", Integer)
+
+ expr2 = column("d1", String) + column("d2", String)
+
+ if reverse:
+ expr = expr2 + expr1
+
+ self.assert_compile(
+ select(expr), "SELECT (d1 || d2) + i1 + i2 AS anon_1"
+ )
+ else:
+ expr = expr1 + expr2
+
+ self.assert_compile(
+ select(expr), "SELECT i1 + i2 + d1 || d2 AS anon_1"
+ )
+
+ @testing.combinations(
+ operators.add,
+ operators.and_,
+ operators.or_,
+ operators.mul,
+ argnames="op",
+ )
+ @testing.combinations(True, False, argnames="reverse")
+ @testing.combinations(True, False, argnames="negate")
+ def test_associatives(self, op, reverse, negate):
+ t1 = table("t", column("q"), column("p"))
+
+ num = 500
+
+ expr = op(t1.c.q, t1.c.p)
+
+ if reverse:
+ for i in range(num - 1, -1, -1):
+ expr = op(column(f"d{i}"), expr)
+ else:
+ for i in range(num):
+ expr = op(expr, column(f"d{i}"))
+
+ opstring = compiler.OPERATORS[op]
+ exprs = opstring.join(f"d{i}" for i in range(num))
+
+ if negate:
+ self.assert_compile(
+ select(~expr),
+ f"SELECT NOT (t.q{opstring}t.p{opstring}{exprs}) "
+ "AS anon_1 FROM t"
+ if not reverse
+ else f"SELECT NOT ({exprs}{opstring}t.q{opstring}t.p) "
+ "AS anon_1 FROM t",
+ )
+ else:
+ self.assert_compile(
+ select(expr),
+ f"SELECT t.q{opstring}t.p{opstring}{exprs} AS anon_1 FROM t"
+ if not reverse
+ else f"SELECT {exprs}{opstring}t.q{opstring}t.p "
+ f"AS anon_1 FROM t",
+ )
+
+ @testing.combinations(
+ operators.gt,
+ operators.eq,
+ operators.le,
+ operators.sub,
+ argnames="op",
+ )
+ @testing.combinations(True, False, argnames="reverse")
+ @testing.combinations(True, False, argnames="negate")
+ def test_non_associatives(self, op, reverse, negate):
+ """similar tests as test_associatives but for non-assoc
+ operators.
+
+ the expressions here don't generally make sense from a SQL
+ perspective, we are checking just that the operators / parenthesis /
+ negation works out in the SQL string to reasonably correspond to
+ what the Python structures look like.
+
+ """
+ t1 = table("t", column("q"), column("p"))
+
+ num = 5
+
+ expr = op(t1.c.q, t1.c.p)
+
+ if reverse:
+ for i in range(num - 1, -1, -1):
+ expr = op(column(f"d{i}"), expr)
+ else:
+ for i in range(num):
+ expr = op(expr, column(f"d{i}"))
+
+ opstring = compiler.OPERATORS[op]
+ exprs = opstring.join(f"d{i}" for i in range(num))
+
+ if negate:
+ negate_op = {
+ operators.gt: operators.le,
+ operators.eq: operators.ne,
+ operators.le: operators.gt,
+ }.get(op, None)
+
+ if negate_op:
+ negate_opstring = compiler.OPERATORS[negate_op]
+ if reverse:
+ str_expr = (
+ f"d0{negate_opstring}(d1{opstring}(d2{opstring}"
+ f"(d3{opstring}(d4{opstring}(t.q{opstring}t.p)))))"
+ )
+ else:
+ str_expr = (
+ f"(((((t.q{opstring}t.p){opstring}d0){opstring}d1)"
+ f"{opstring}d2){opstring}d3){negate_opstring}d4"
+ )
+ else:
+ if reverse:
+ str_expr = (
+ f"NOT (d0{opstring}(d1{opstring}(d2{opstring}"
+ f"(d3{opstring}(d4{opstring}(t.q{opstring}t.p))))))"
+ )
+ else:
+ str_expr = (
+ f"NOT ((((((t.q{opstring}t.p){opstring}d0)"
+ f"{opstring}d1){opstring}d2){opstring}d3){opstring}d4)"
+ )
+
+ self.assert_compile(
+ select(~expr),
+ f"SELECT {str_expr} AS anon_1 FROM t"
+ if not reverse
+ else f"SELECT {str_expr} AS anon_1 FROM t",
+ )
+ else:
+
+ if reverse:
+ str_expr = (
+ f"d0{opstring}(d1{opstring}(d2{opstring}"
+ f"(d3{opstring}(d4{opstring}(t.q{opstring}t.p)))))"
+ )
+ else:
+ str_expr = (
+ f"(((((t.q{opstring}t.p){opstring}d0)"
+ f"{opstring}d1){opstring}d2){opstring}d3){opstring}d4"
+ )
+
+ self.assert_compile(
+ select(expr),
+ f"SELECT {str_expr} AS anon_1 FROM t"
+ if not reverse
+ else f"SELECT {str_expr} AS anon_1 FROM t",
+ )
+
+
class CustomUnaryOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL):
__dialect__ = "default"
@@ -2954,7 +3139,7 @@ class ComposedLikeOperatorsTest(fixtures.TestBase, testing.AssertsCompiledSQL):
def test_contains_concat(self):
self.assert_compile(
column("x").contains("y"),
- "x LIKE concat(concat('%%', %s), '%%')",
+ "x LIKE concat('%%', %s, '%%')",
checkparams={"x_1": "y"},
dialect=mysql.dialect(),
)
@@ -2962,7 +3147,7 @@ class ComposedLikeOperatorsTest(fixtures.TestBase, testing.AssertsCompiledSQL):
def test_not_contains_concat(self):
self.assert_compile(
~column("x").contains("y"),
- "x NOT LIKE concat(concat('%%', %s), '%%')",
+ "x NOT LIKE concat('%%', %s, '%%')",
checkparams={"x_1": "y"},
dialect=mysql.dialect(),
)
@@ -2970,7 +3155,7 @@ class ComposedLikeOperatorsTest(fixtures.TestBase, testing.AssertsCompiledSQL):
def test_contains_literal_concat(self):
self.assert_compile(
column("x").contains(literal_column("y")),
- "x LIKE concat(concat('%%', y), '%%')",
+ "x LIKE concat('%%', y, '%%')",
checkparams={},
dialect=mysql.dialect(),
)
@@ -2978,7 +3163,7 @@ class ComposedLikeOperatorsTest(fixtures.TestBase, testing.AssertsCompiledSQL):
def test_contains_text_concat(self):
self.assert_compile(
column("x").contains(text("y")),
- "x LIKE concat(concat('%%', y), '%%')",
+ "x LIKE concat('%%', y, '%%')",
checkparams={},
dialect=mysql.dialect(),
)