diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2011-09-05 19:12:12 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2011-09-05 19:12:12 -0400 |
| commit | 8c0e82238c39ee068a5fe143d06c5b681127d62f (patch) | |
| tree | 35d6401fb245f01a778cbce76378978f06c39db4 /test | |
| parent | 56e374776dfc5e6d371a27e24dc2646c844f4c0f (diff) | |
| download | sqlalchemy-8c0e82238c39ee068a5fe143d06c5b681127d62f.tar.gz | |
- Fixed bug regarding calculation of "from" list
for a select() element. The "from" calc is now
delayed, so that if the construct uses a Column
object that is not yet attached to a Table,
but is later associated with a Table, it generates
SQL using the table as a FROM. This change
impacted fairly deeply the mechanics of how
the FROM list as well as the "correlates" collection
is calculated, as some "clause adaption" schemes
(these are used very heavily in the ORM)
were relying upon the fact that the "froms"
collection would typically be cached before the
adaption completed. The rework allows it
such that the "froms" collection can be cleared
and re-generated at any time. [ticket:2261]
- RelationshipProperty.Comparator._criterion_exists()
adds an "_orm_adapt" annotation to the correlates target,
to work with the change in [ticket:2261]. It's not clear
if the change to correlation+adaption mechanics will affect end user
code yet.
- FromClause now uses group_expirable_memoized_property for
late-generated values like primary key, _columns, etc.
The Select class adds some tokens to this object and has the
nice effect that FromClause doesn't need to know about
Select's names anymore. An additional change might be to
have Select use a different group_expirable_memoized_property
so that it's collection of attribute names are specific to
Select though this isn't really necessary right now.
Diffstat (limited to 'test')
| -rw-r--r-- | test/orm/inheritance/test_query.py | 7 | ||||
| -rw-r--r-- | test/orm/test_selectable.py | 1 | ||||
| -rw-r--r-- | test/sql/test_selectable.py | 117 |
3 files changed, 114 insertions, 11 deletions
diff --git a/test/orm/inheritance/test_query.py b/test/orm/inheritance/test_query.py index 2560d2284..94dde71f8 100644 --- a/test/orm/inheritance/test_query.py +++ b/test/orm/inheritance/test_query.py @@ -186,13 +186,6 @@ def _produce_test(select_type): eq_(sess.query(Person).all(), all_employees) self.assert_sql_count(testing.db, go, {'':14, 'Polymorphic':9}.get(select_type, 10)) - def test_foo(self): - sess = create_session() - - def go(): - eq_(sess.query(Person).options(subqueryload(Engineer.machines)).all(), all_employees) - self.assert_sql_count(testing.db, go, {'':14, 'Unions':8, 'Polymorphic':7}.get(select_type, 8)) - def test_primary_eager_aliasing(self): sess = create_session() diff --git a/test/orm/test_selectable.py b/test/orm/test_selectable.py index 7e4a92de1..97849f845 100644 --- a/test/orm/test_selectable.py +++ b/test/orm/test_selectable.py @@ -60,7 +60,6 @@ class SelectableNoFromsTest(fixtures.MappedTest, AssertsCompiledSQL): subset_select = select([common.c.id, common.c.data]).alias() subset_mapper = mapper(Subset, subset_select) - sess = Session(bind=testing.db) sess.add(Subset(data=1)) sess.flush() diff --git a/test/sql/test_selectable.py b/test/sql/test_selectable.py index 82d018af1..9c1f44e1a 100644 --- a/test/sql/test_selectable.py +++ b/test/sql/test_selectable.py @@ -64,16 +64,16 @@ class SelectableTest(fixtures.TestBase, AssertsExecutionResults, AssertsCompiled assert s1.corresponding_column(scalar_select) is s1.c.foo assert s2.corresponding_column(scalar_select) is s2.c.foo - + def test_label_grouped_still_corresponds(self): label = select([table1.c.col1]).label('foo') label2 = label.self_group() - + s1 = select([label]) s2 = select([label2]) assert s1.corresponding_column(label) is s1.c.foo assert s2.corresponding_column(label) is s2.c.foo - + def test_direct_correspondence_on_labels(self): # this test depends on labels being part # of the proxy set to get the right result @@ -376,6 +376,117 @@ class SelectableTest(fixtures.TestBase, AssertsExecutionResults, AssertsCompiled [s.c.col1, s.corresponding_column(c2)] ) + def test_from_list_deferred_constructor(self): + c1 = Column('c1', Integer) + c2 = Column('c2', Integer) + + s = select([c1]) + + t = Table('t', MetaData(), c1, c2) + + eq_(c1._from_objects, [t]) + eq_(c2._from_objects, [t]) + + self.assert_compile(select([c1]), + "SELECT t.c1 FROM t") + self.assert_compile(select([c2]), + "SELECT t.c2 FROM t") + + def test_from_list_deferred_whereclause(self): + c1 = Column('c1', Integer) + c2 = Column('c2', Integer) + + s = select([c1]).where(c1==5) + + t = Table('t', MetaData(), c1, c2) + + eq_(c1._from_objects, [t]) + eq_(c2._from_objects, [t]) + + self.assert_compile(select([c1]), + "SELECT t.c1 FROM t") + self.assert_compile(select([c2]), + "SELECT t.c2 FROM t") + + def test_from_list_deferred_fromlist(self): + m = MetaData() + t1 = Table('t1', m, Column('x', Integer)) + + c1 = Column('c1', Integer) + s = select([c1]).where(c1==5).select_from(t1) + + t2 = Table('t2', MetaData(), c1) + + eq_(c1._from_objects, [t2]) + + self.assert_compile(select([c1]), + "SELECT t2.c1 FROM t2") + + def test_from_list_deferred_cloning(self): + c1 = Column('c1', Integer) + c2 = Column('c2', Integer) + + s = select([c1]) + s2 = select([c2]) + s3 = sql_util.ClauseAdapter(s).traverse(s2) + + # the adaptation process needs the full + # FROM list so can't avoid the warning on + # this one + assert_raises_message( + exc.SAWarning, + r"\<class 'sqlalchemy.schema.Table'\> being associated ", + Table, 't', MetaData(), c1 + ) + + def test_from_list_warning_against_existing(self): + c1 = Column('c1', Integer) + s = select([c1]) + + # force a compile. + eq_(str(s), "SELECT c1") + + # this will emit a warning + assert_raises_message( + exc.SAWarning, + r"\<class 'sqlalchemy.schema.Table'\> being associated " + r"with \<class 'sqlalchemy.schema.Column'\> object after " + r"the \<class 'sqlalchemy.schema.Column'\> has already " + r"been used in a SQL generation; previously " + r"generated constructs may contain stale state.", + Table, 't', MetaData(), c1 + ) + + def test_from_list_recovers_after_warning(self): + c1 = Column('c1', Integer) + c2 = Column('c2', Integer) + + s = select([c1]) + + # force a compile. + eq_(str(s), "SELECT c1") + + @testing.emits_warning() + def go(): + return Table('t', MetaData(), c1, c2) + t = go() + + eq_(c1._from_objects, [t]) + eq_(c2._from_objects, [t]) + + # 's' has been baked. Can't afford + # not caching select._froms. + # hopefully the warning will clue the user + self.assert_compile(s, "SELECT t.c1") + self.assert_compile(select([c1]), "SELECT t.c1 FROM t") + self.assert_compile(select([c2]), "SELECT t.c2 FROM t") + + def test_label_gen_resets_on_table(self): + c1 = Column('c1', Integer) + eq_(c1._label, "c1") + Table('t1', MetaData(), c1) + eq_(c1._label, "t1_c1") + class AnonLabelTest(fixtures.TestBase): """Test behaviors that we hope to change with [ticket:2168].""" |
