more tuning on any()

Issue #2494 resolved
Mike Bayer repo owner created an issue

need tests for this:

diff -r e2c612d24d714ba2a4fb805d9e7bdb9023dc0af8 lib/sqlalchemy/orm/properties.py
--- a/lib/sqlalchemy/orm/properties.py  Thu May 24 11:12:39 2012 -0400
+++ b/lib/sqlalchemy/orm/properties.py  Thu May 24 12:28:56 2012 -0400
@@ -460,8 +460,24 @@

             crit = j & criterion

+            s = sql.exists([1](1), crit, from_obj=dest)
+
+            # source table, might be annotated already.
+            tables = set([source](source))
+
+            # add in other tables on the "local side" 
+            # of the property.  This helps when joining
+            # from a joined-inh model.
+            tables.update(c.table for c in 
+                        self.property.local_columns)
+
+            # set them up as correlated.
+            correlate = [               table._annotate({'_orm_adapt':True})
+                for table in tables
+            ](
+)
             return sql.exists([1](1), crit, from_obj=dest).\
-                            correlate(source._annotate({'_orm_adapt':True}))
+                            correlate(*correlate)

         def any(self, criterion=None, **kwargs):
             """Produce an expression that tests a collection against
diff -r e2c612d24d714ba2a4fb805d9e7bdb9023dc0af8 lib/sqlalchemy/sql/expression.py
--- a/lib/sqlalchemy/sql/expression.py  Thu May 24 11:12:39 2012 -0400
+++ b/lib/sqlalchemy/sql/expression.py  Thu May 24 12:28:56 2012 -0400
@@ -3496,9 +3496,9 @@
     def select(self, whereclause=None, **params):
         return select([self](self), whereclause, **params)

-    def correlate(self, fromclause):
+    def correlate(self, *fromclauses):
         e = self._clone()
-        e.element = self.element.correlate(fromclause).self_group()
+        e.element = self.element.correlate(*fromclauses).self_group()
         return e

     def select_from(self, clause):

the current test case is:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base= declarative_base()

class CommonObject(Base):
    __tablename__ = "objects"
    id = Column(Integer, primary_key=True)
    objname = Column(String(32))

class GoodsPlacement(CommonObject):
    __tablename__ = "goods_placements"
    id = Column(Integer, ForeignKey("objects.id"),  primary_key=True)

class Departure(CommonObject):
    __tablename__ = "departures"
    id = Column(Integer, ForeignKey("objects.id"),  primary_key=True)
    content_id = Column(Integer, ForeignKey("goods_placements.id"))
    status_id = Column(Integer)
    content = relationship("GoodsPlacement",
        foreign_keys=[content_id](content_id),
        lazy='joined',
        backref="departures"
        )
    __mapper_args__ = {'inherit_condition':id==CommonObject.id}

session = Session()
print session.query(GoodsPlacement).filter(~GoodsPlacement.departures.any(Departure.status_id < 2))

# is it safe to work on explicitly "local_columns" like that ?  
# aliasing seems covered by the fact that the 
# "x join y" is immediately wrapped in a subquery:
gp = aliased(GoodsPlacement)
print session.query(gp).filter(~gp.departures.any(Departure.status_id < 2))

# but is it possible that the "local_columns" would work their way onto the "remote side" in some strange self-referential case ?   or would they always be wrapped in a subq in such a case (I think so?)

Comments (2)

  1. Mike Bayer reporter

    unfortunately I can't figure out if there was an issue here, as the above test case illustrates no issue. Both with the patch, and without, the two queries generated above render exactly the same, not just in 0.8 but in 0.7 also, and I think even in 0.6 with a previous test. I remember this is from a stack overflow issue but I can't locate it anymore. There's no action I can take here since I don't have any test case that does anything, though I definitely recall thinking I saw something.

  2. Log in to comment