summaryrefslogtreecommitdiff
path: root/test/sql/test_selectable.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-04-22 19:43:31 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-04-22 19:43:31 -0400
commit713a4e19fa6c4397191dd7311152c6c69c37535e (patch)
treecc73d61aa1275e65378f0c618ee3756836ac943e /test/sql/test_selectable.py
parent02e8d401fea0c77a60efcdd1138cf29b30384219 (diff)
parent35adeb95bf917330e1366f8a7252999419819fb1 (diff)
downloadsqlalchemy-713a4e19fa6c4397191dd7311152c6c69c37535e.tar.gz
- merged #1401 branch from bitbucket
- resolved some serious speed hits I missed, we need to ensure only deannotated columns are used in the local/remote collections and soforth so that hash lookups against mapped columns don't dig into __eq__() - fix some other parity mismatches regarding stuff from [ticket:2453], including finding another case where _deep_annotate() was doing the wrong thing, new tests. - [feature] Major rewrite of relationship() internals now allow join conditions which include columns pointing to themselves within composite foreign keys. A new API for very specialized primaryjoin conditions is added, allowing conditions based on SQL functions, CAST, etc. to be handled by placing the annotation functions remote() and foreign() inline within the expression when necessary. Previous recipes using the semi-private _local_remote_pairs approach can be upgraded to this new approach. [ticket:1401]
Diffstat (limited to 'test/sql/test_selectable.py')
-rw-r--r--test/sql/test_selectable.py98
1 files changed, 91 insertions, 7 deletions
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