summaryrefslogtreecommitdiff
path: root/test/sql
diff options
context:
space:
mode:
Diffstat (limited to 'test/sql')
-rw-r--r--test/sql/test_generative.py98
-rw-r--r--test/sql/test_selectable.py98
2 files changed, 188 insertions, 8 deletions
diff --git a/test/sql/test_generative.py b/test/sql/test_generative.py
index 98e783ede..29b7cd482 100644
--- a/test/sql/test_generative.py
+++ b/test/sql/test_generative.py
@@ -1,5 +1,5 @@
from sqlalchemy import *
-from sqlalchemy.sql import table, column, ClauseElement
+from sqlalchemy.sql import table, column, ClauseElement, operators
from sqlalchemy.sql.expression import _clone, _from_objects
from test.lib import *
from sqlalchemy.sql.visitors import *
@@ -166,6 +166,102 @@ class TraversalTest(fixtures.TestBase, AssertsExecutionResults):
s = set(ClauseVisitor().iterate(bin))
assert set(ClauseVisitor().iterate(bin)) == set([foo, bar, bin])
+class BinaryEndpointTraversalTest(fixtures.TestBase):
+ """test the special binary product visit"""
+
+ def _assert_traversal(self, expr, expected):
+ canary = []
+ def visit(binary, l, r):
+ canary.append((binary.operator, l, r))
+ print binary.operator, l, r
+ sql_util.visit_binary_product(visit, expr)
+ eq_(
+ canary, expected
+ )
+
+ def test_basic(self):
+ a, b = column("a"), column("b")
+ self._assert_traversal(
+ a == b,
+ [
+ (operators.eq, a, b)
+ ]
+ )
+
+ def test_with_tuples(self):
+ a, b, c, d, b1, b1a, b1b, e, f = (
+ column("a"),
+ column("b"),
+ column("c"),
+ column("d"),
+ column("b1"),
+ column("b1a"),
+ column("b1b"),
+ column("e"),
+ column("f")
+ )
+ expr = tuple_(
+ a, b, b1==tuple_(b1a, b1b == d), c
+ ) > tuple_(
+ func.go(e + f)
+ )
+ self._assert_traversal(
+ expr,
+ [
+ (operators.gt, a, e),
+ (operators.gt, a, f),
+ (operators.gt, b, e),
+ (operators.gt, b, f),
+ (operators.eq, b1, b1a),
+ (operators.eq, b1b, d),
+ (operators.gt, c, e),
+ (operators.gt, c, f)
+ ]
+ )
+
+ def test_composed(self):
+ a, b, e, f, q, j, r = (
+ column("a"),
+ column("b"),
+ column("e"),
+ column("f"),
+ column("q"),
+ column("j"),
+ column("r"),
+ )
+ expr = and_(
+ (a + b) == q + func.sum(e + f),
+ and_(
+ j == r,
+ f == q
+ )
+ )
+ self._assert_traversal(
+ expr,
+ [
+ (operators.eq, a, q),
+ (operators.eq, a, e),
+ (operators.eq, a, f),
+ (operators.eq, b, q),
+ (operators.eq, b, e),
+ (operators.eq, b, f),
+ (operators.eq, j, r),
+ (operators.eq, f, q),
+ ]
+ )
+
+ def test_subquery(self):
+ a, b, c = column("a"), column("b"), column("c")
+ subq = select([c]).where(c == a).as_scalar()
+ expr = and_(a == b, b == subq)
+ self._assert_traversal(
+ expr,
+ [
+ (operators.eq, a, b),
+ (operators.eq, b, subq),
+ ]
+ )
+
class ClauseTest(fixtures.TestBase, AssertsCompiledSQL):
"""test copy-in-place behavior of various ClauseElements."""
diff --git a/test/sql/test_selectable.py b/test/sql/test_selectable.py
index bbb9131a5..dde832e7d 100644
--- a/test/sql/test_selectable.py
+++ b/test/sql/test_selectable.py
@@ -1023,6 +1023,25 @@ class AnnotationsTest(fixtures.TestBase):
annot = obj._annotate({})
eq_(set([obj]), set([annot]))
+ def test_compare(self):
+ t = table('t', column('x'), column('y'))
+ x_a = t.c.x._annotate({})
+ assert t.c.x.compare(x_a)
+ assert x_a.compare(t.c.x)
+ assert not x_a.compare(t.c.y)
+ assert not t.c.y.compare(x_a)
+ assert (t.c.x == 5).compare(x_a == 5)
+ assert not (t.c.y == 5).compare(x_a == 5)
+
+ s = select([t])
+ x_p = s.c.x
+ assert not x_a.compare(x_p)
+ assert not t.c.x.compare(x_p)
+ x_p_a = x_p._annotate({})
+ assert x_p_a.compare(x_p)
+ assert x_p.compare(x_p_a)
+ assert not x_p_a.compare(x_a)
+
def test_custom_constructions(self):
from sqlalchemy.schema import Column
class MyColumn(Column):
@@ -1132,13 +1151,18 @@ class AnnotationsTest(fixtures.TestBase):
assert b2.left is not bin.left
assert b3.left is not b2.left is not bin.left
assert b4.left is bin.left # since column is immutable
- assert b4.right is not bin.right is not b2.right is not b3.right
+ # deannotate copies the element
+ assert bin.right is not b2.right is not b3.right is not b4.right
def test_annotate_unique_traversal(self):
"""test that items are copied only once during
annotate, deannotate traversal
- #2453
+ #2453 - however note this was modified by
+ #1401, and it's likely that re49563072578
+ is helping us with the str() comparison
+ case now, as deannotate is making
+ clones again in some cases.
"""
table1 = table('table1', column('x'))
table2 = table('table2', column('y'))
@@ -1146,21 +1170,81 @@ class AnnotationsTest(fixtures.TestBase):
s = select([a1.c.x]).select_from(
a1.join(table2, a1.c.x==table2.c.y)
)
-
for sel in (
sql_util._deep_deannotate(s),
- sql_util._deep_annotate(s, {'foo':'bar'}),
visitors.cloned_traverse(s, {}, {}),
visitors.replacement_traverse(s, {}, lambda x:None)
):
# the columns clause isn't changed at all
assert sel._raw_columns[0].table is a1
- # the from objects are internally consistent,
- # i.e. the Alias at position 0 is the same
- # Alias in the Join object in position 1
assert sel._froms[0] is sel._froms[1].left
+
+ eq_(str(s), str(sel))
+
+ # when we are modifying annotations sets only
+ # partially, each element is copied unconditionally
+ # when encountered.
+ for sel in (
+ sql_util._deep_deannotate(s, {"foo":"bar"}),
+ sql_util._deep_annotate(s, {'foo':'bar'}),
+ ):
+ assert sel._froms[0] is not sel._froms[1].left
+
+ # but things still work out due to
+ # re49563072578
eq_(str(s), str(sel))
+
+ def test_annotate_varied_annot_same_col(self):
+ """test two instances of the same column with different annotations
+ preserving them when deep_annotate is run on them.
+
+ """
+ t1 = table('table1', column("col1"), column("col2"))
+ s = select([t1.c.col1._annotate({"foo":"bar"})])
+ s2 = select([t1.c.col1._annotate({"bat":"hoho"})])
+ s3 = s.union(s2)
+ sel = sql_util._deep_annotate(s3, {"new":"thing"})
+
+ eq_(
+ sel.selects[0]._raw_columns[0]._annotations,
+ {"foo":"bar", "new":"thing"}
+ )
+
+ eq_(
+ sel.selects[1]._raw_columns[0]._annotations,
+ {"bat":"hoho", "new":"thing"}
+ )
+
+ def test_deannotate_2(self):
+ table1 = table('table1', column("col1"), column("col2"))
+ j = table1.c.col1._annotate({"remote":True}) == \
+ table1.c.col2._annotate({"local":True})
+ j2 = sql_util._deep_deannotate(j)
+ eq_(
+ j.left._annotations, {"remote":True}
+ )
+ eq_(
+ j2.left._annotations, {}
+ )
+
+ def test_deannotate_3(self):
+ table1 = table('table1', column("col1"), column("col2"),
+ column("col3"), column("col4"))
+ j = and_(
+ table1.c.col1._annotate({"remote":True})==
+ table1.c.col2._annotate({"local":True}),
+ table1.c.col3._annotate({"remote":True})==
+ table1.c.col4._annotate({"local":True})
+ )
+ j2 = sql_util._deep_deannotate(j)
+ eq_(
+ j.clauses[0].left._annotations, {"remote":True}
+ )
+ eq_(
+ j2.clauses[0].left._annotations, {}
+ )
+
def test_annotate_fromlist_preservation(self):
"""test the FROM list in select still works
even when multiple annotate runs have created