[Sqlalchemy-commits] [5795] sqlalchemy/trunk: - Fixed bugs in Query regarding simultaneous selectio
Brought to you by:
zzzeek
From: <co...@sq...> - 2009-02-13 17:14:11
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li, #header, #footer { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[5795] sqlalchemy/trunk: - Fixed bugs in Query regarding simultaneous selection of </title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>5795</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2009-02-13 12:14:05 -0500 (Fri, 13 Feb 2009)</dd> </dl> <h3>Log Message</h3> <pre>- Fixed bugs in Query regarding simultaneous selection of multiple joined-table inheritance entities with common base classes, previously the adaption applied to "e2" on "e1 JOIN e2" would be partially applied to "e1". Additionally, comparisons on relations (i.e. Entity2.related==e2) were not getting adapted correctly.</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunkCHANGES">sqlalchemy/trunk/CHANGES</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyormpropertiespy">sqlalchemy/trunk/lib/sqlalchemy/orm/properties.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyormquerypy">sqlalchemy/trunk/lib/sqlalchemy/orm/query.py</a></li> <li><a href="#sqlalchemytrunktestorminheritancequerypy">sqlalchemy/trunk/test/orm/inheritance/query.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkCHANGES"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/CHANGES (5794 => 5795)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/CHANGES 2009-02-13 05:38:39 UTC (rev 5794) +++ sqlalchemy/trunk/CHANGES 2009-02-13 17:14:05 UTC (rev 5795) </span><span class="lines">@@ -32,6 +32,13 @@ </span><span class="cx"> so that the "listen_for_events.py" example works again. </span><span class="cx"> [ticket:1314] </span><span class="cx"> </span><ins>+ - Fixed bugs in Query regarding simultaneous selection of + multiple joined-table inheritance entities with common base + classes, previously the adaption applied to "e2" on + "e1 JOIN e2" would be partially applied to "e1". Additionally, + comparisons on relations (i.e. Entity2.related==e2) + were not getting adapted correctly. + </ins><span class="cx"> - sql </span><span class="cx"> - Fixed missing _label attribute on Function object, others </span><span class="cx"> when used in a select() with use_labels (such as when used </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyormpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/orm/properties.py (5794 => 5795)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/orm/properties.py 2009-02-13 05:38:39 UTC (rev 5794) +++ sqlalchemy/trunk/lib/sqlalchemy/orm/properties.py 2009-02-13 17:14:05 UTC (rev 5795) </span><span class="lines">@@ -485,11 +485,11 @@ </span><span class="cx"> if self.property.direction in [ONETOMANY, MANYTOMANY]: </span><span class="cx"> return ~self._criterion_exists() </span><span class="cx"> else: </span><del>- return self.property._optimized_compare(None, adapt_source=self.adapter) </del><ins>+ return _orm_annotate(self.property._optimized_compare(None, adapt_source=self.adapter)) </ins><span class="cx"> elif self.property.uselist: </span><span class="cx"> raise sa_exc.InvalidRequestError("Can't compare a collection to an object or collection; use contains() to test for membership.") </span><span class="cx"> else: </span><del>- return self.property._optimized_compare(other, adapt_source=self.adapter) </del><ins>+ return _orm_annotate(self.property._optimized_compare(other, adapt_source=self.adapter)) </ins><span class="cx"> </span><span class="cx"> def _criterion_exists(self, criterion=None, **kwargs): </span><span class="cx"> if getattr(self, '_of_type', None): </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyormquerypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/orm/query.py (5794 => 5795)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/orm/query.py 2009-02-13 05:38:39 UTC (rev 5794) +++ sqlalchemy/trunk/lib/sqlalchemy/orm/query.py 2009-02-13 17:14:05 UTC (rev 5795) </span><span class="lines">@@ -127,6 +127,7 @@ </span><span class="cx"> </span><span class="cx"> def __mapper_loads_polymorphically_with(self, mapper, adapter): </span><span class="cx"> for m2 in mapper._with_polymorphic_mappers: </span><ins>+ self._polymorphic_adapters[m2] = adapter </ins><span class="cx"> for m in m2.iterate_to_root(): </span><span class="cx"> self._polymorphic_adapters[m.mapped_table] = self._polymorphic_adapters[m.local_table] = adapter </span><span class="cx"> </span><span class="lines">@@ -145,6 +146,7 @@ </span><span class="cx"> </span><span class="cx"> def _reset_polymorphic_adapter(self, mapper): </span><span class="cx"> for m2 in mapper._with_polymorphic_mappers: </span><ins>+ self._polymorphic_adapters.pop(m2, None) </ins><span class="cx"> for m in m2.iterate_to_root(): </span><span class="cx"> self._polymorphic_adapters.pop(m.mapped_table, None) </span><span class="cx"> self._polymorphic_adapters.pop(m.local_table, None) </span><span class="lines">@@ -1892,10 +1894,7 @@ </span><span class="cx"> </span><span class="cx"> adapter = None </span><span class="cx"> if not self.is_aliased_class and query._polymorphic_adapters: </span><del>- for mapper in self.mapper.iterate_to_root(): - adapter = query._polymorphic_adapters.get(mapper.mapped_table, None) - if adapter: - break </del><ins>+ adapter = query._polymorphic_adapters.get(self.mapper, None) </ins><span class="cx"> </span><span class="cx"> if not adapter and self.adapter: </span><span class="cx"> adapter = self.adapter </span></span></pre></div> <a id="sqlalchemytrunktestorminheritancequerypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/orm/inheritance/query.py (5794 => 5795)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/orm/inheritance/query.py 2009-02-13 05:38:39 UTC (rev 5794) +++ sqlalchemy/trunk/test/orm/inheritance/query.py 2009-02-13 17:14:05 UTC (rev 5795) </span><span class="lines">@@ -9,6 +9,8 @@ </span><span class="cx"> from sqlalchemy import exc as sa_exc </span><span class="cx"> from testlib import * </span><span class="cx"> from testlib import fixtures </span><ins>+from orm import _base +from testlib.testing import eq_ </ins><span class="cx"> from sqlalchemy.ext.declarative import declarative_base </span><span class="cx"> from sqlalchemy.engine import default </span><span class="cx"> </span><span class="lines">@@ -773,7 +775,7 @@ </span><span class="cx"> </span><span class="cx"> mapper(Engineer, engineers, inherits=Person, </span><span class="cx"> polymorphic_identity='engineer', properties={ </span><del>- 'reports_to':relation(Manager, primaryjoin=managers.c.person_id==engineers.c.reports_to_id) </del><ins>+ 'reports_to':relation(Manager, primaryjoin=managers.c.person_id==engineers.c.reports_to_id, backref='engineers') </ins><span class="cx"> }) </span><span class="cx"> </span><span class="cx"> def test_has(self): </span><span class="lines">@@ -800,7 +802,34 @@ </span><span class="cx"> self.assertEquals( </span><span class="cx"> sess.query(Engineer).join('reports_to', aliased=True).filter(Manager.name=='dogbert').first(), </span><span class="cx"> Engineer(name='dilbert')) </span><ins>+ + def test_relation_compare(self): + m1 = Manager(name='dogbert') + m2 = Manager(name='foo') + e1 = Engineer(name='dilbert', primary_language='java', reports_to=m1) + e2 = Engineer(name='wally', primary_language='c++', reports_to=m2) + e3 = Engineer(name='etc', primary_language='c++') + sess = create_session() + sess.add(m1) + sess.add(m2) + sess.add(e1) + sess.add(e2) + sess.add(e3) + sess.flush() + sess.expunge_all() + + self.assertEquals( + sess.query(Manager).join(Manager.engineers).filter(Engineer.reports_to==None).all(), + [] + ) + + self.assertEquals( + sess.query(Manager).join(Manager.engineers).filter(Engineer.reports_to==m1).all(), + [m1] + ) </ins><span class="cx"> </span><ins>+ + </ins><span class="cx"> </span><span class="cx"> class M2MFilterTest(ORMTest): </span><span class="cx"> keep_mappers = True </span><span class="lines">@@ -868,6 +897,8 @@ </span><span class="cx"> self.assertEquals(sess.query(Organization).filter(Organization.engineers.any(Engineer.name=='e1')).all(), [Organization(name='org1')]) </span><span class="cx"> </span><span class="cx"> class SelfReferentialM2MTest(ORMTest, AssertsCompiledSQL): </span><ins>+ keep_mappers = True + </ins><span class="cx"> def define_tables(self, metadata): </span><span class="cx"> Base = declarative_base(metadata=metadata) </span><span class="cx"> </span><span class="lines">@@ -895,9 +926,50 @@ </span><span class="cx"> Child1.left_child2 = relation(Child2, secondary = secondary_table, </span><span class="cx"> primaryjoin = Parent.id == secondary_table.c.right_id, </span><span class="cx"> secondaryjoin = Parent.id == secondary_table.c.left_id, </span><del>- uselist = False, </del><ins>+ uselist = False, backref="right_children" </ins><span class="cx"> ) </span><span class="cx"> </span><ins>+ + def test_query_crit(self): + session = create_session() + c11, c12, c13 = Child1(), Child1(), Child1() + c21, c22, c23 = Child2(), Child2(), Child2() + + c11.left_child2 = c22 + c12.left_child2 = c22 + c13.left_child2 = c23 + + session.add_all([c11, c12, c13, c21, c22, c23]) + session.flush() + + # test that the join to Child2 doesn't alias Child1 in the select + eq_( + set(session.query(Child1).join(Child1.left_child2)), + set([c11, c12, c13]) + ) + + eq_( + set(session.query(Child1, Child2).join(Child1.left_child2)), + set([(c11, c22), (c12, c22), (c13, c23)]) + ) + + # test __eq__() on property is annotating correctly + eq_( + set(session.query(Child2).join(Child2.right_children).filter(Child1.left_child2==c22)), + set([c22]) + ) + + # test the same again + self.assert_compile( + session.query(Child2).join(Child2.right_children).filter(Child1.left_child2==c22).with_labels().statement, + "SELECT parent.id AS parent_id, child2.id AS child2_id, parent.cls AS parent_cls FROM " + "secondary AS secondary_1, parent JOIN child2 ON parent.id = child2.id JOIN secondary AS secondary_2 " + "ON parent.id = secondary_2.left_id JOIN (SELECT parent.id AS parent_id, parent.cls AS parent_cls, " + "child1.id AS child1_id FROM parent JOIN child1 ON parent.id = child1.id) AS anon_1 ON " + "anon_1.parent_id = secondary_2.right_id WHERE anon_1.parent_id = secondary_1.right_id AND :param_1 = secondary_1.left_id", + dialect=default.DefaultDialect() + ) + </ins><span class="cx"> def test_eager_join(self): </span><span class="cx"> session = create_session() </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |