summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2008-02-09 01:48:19 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2008-02-09 01:48:19 +0000
commit1a3dc519930712d2e6de095a07d76da9a9062210 (patch)
tree2587b92dde7ddba71b369ad1b88c7e0e296470cc /lib/sqlalchemy
parent0b890e1ccde7da937a25107d9287d4dc4e5b7775 (diff)
downloadsqlalchemy-1a3dc519930712d2e6de095a07d76da9a9062210.tar.gz
- lazy loader can now handle a join condition where the "bound"
column (i.e. the one that gets the parent id sent as a bind parameter) appears more than once in the join condition. Specifically this allows the common task of a relation() which contains a parent-correlated subquery, such as "select only the most recent child item". [ticket:946] - col_is_part_of_mappings made more strict, seems to be OK with tests - memusage will dump out the size list in an assertion fail
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/orm/properties.py20
-rw-r--r--lib/sqlalchemy/orm/strategies.py16
2 files changed, 23 insertions, 13 deletions
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index a7932bfc5..d08dd7124 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -494,19 +494,19 @@ class PropertyLoader(StrategizedProperty):
if vis.result:
raise exceptions.ArgumentError("In relationship '%s', primary and secondary join conditions must not include columns from the polymorphic 'select_table' argument as of SA release 0.3.4. Construct join conditions using the base tables of the related mappers." % (str(self)))
+ def _col_is_part_of_mappings(self, column):
+ if self.secondary is None:
+ return self.parent.mapped_table.c.contains_column(column) or \
+ self.target.c.contains_column(column)
+ else:
+ return self.parent.mapped_table.c.contains_column(column) or \
+ self.target.c.contains_column(column) or \
+ self.secondary.c.contains_column(column) is not None
+
def _determine_fks(self):
if self._legacy_foreignkey and not self._is_self_referential():
self.foreign_keys = self._legacy_foreignkey
- def col_is_part_of_mappings(col):
- if self.secondary is None:
- return self.parent.mapped_table.corresponding_column(col) is not None or \
- self.target.corresponding_column(col) is not None
- else:
- return self.parent.mapped_table.corresponding_column(col) is not None or \
- self.target.corresponding_column(col) is not None or \
- self.secondary.corresponding_column(col) is not None
-
if self.foreign_keys:
self._opposite_side = util.Set()
def visit_binary(binary):
@@ -529,7 +529,7 @@ class PropertyLoader(StrategizedProperty):
# this check is for when the user put the "view_only" flag on and has tables that have nothing
# to do with the relationship's parent/child mappings in the join conditions. we dont want cols
# or clauses related to those external tables dealt with. see orm.relationships.ViewOnlyTest
- if not col_is_part_of_mappings(binary.left) or not col_is_part_of_mappings(binary.right):
+ if not self._col_is_part_of_mappings(binary.left) or not self._col_is_part_of_mappings(binary.right):
return
for f in binary.left.foreign_keys:
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 3b3c86d1a..bdc8ab9a9 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -265,7 +265,7 @@ NoLoader.logger = logging.class_logger(NoLoader)
class LazyLoader(AbstractRelationLoader):
def init(self):
super(LazyLoader, self).init()
- (self.lazywhere, self.lazybinds, self.equated_columns) = self._create_lazy_clause(self)
+ (self.lazywhere, self.lazybinds, self.equated_columns) = self._create_lazy_clause(self.parent_property)
self.logger.info(str(self.parent_property) + " lazy loading clause " + str(self.lazywhere))
@@ -366,6 +366,9 @@ class LazyLoader(AbstractRelationLoader):
equated_columns = {}
def should_bind(targetcol, othercol):
+ if not prop._col_is_part_of_mappings(targetcol):
+ return False
+
if reverse_direction and not secondaryjoin:
return targetcol in remote_side
else:
@@ -381,13 +384,20 @@ class LazyLoader(AbstractRelationLoader):
equated_columns[leftcol] = rightcol
if should_bind(leftcol, rightcol):
- binary.left = binds[leftcol] = sql.bindparam(None, None, type_=binary.right.type)
+ if leftcol in binds:
+ binary.left = binds[leftcol]
+ else:
+ binary.left = binds[leftcol] = sql.bindparam(None, None, type_=binary.right.type)
# the "left is not right" compare is to handle part of a join clause that is "table.c.col1==table.c.col1",
# which can happen in rare cases (test/orm/relationships.py RelationTest2)
if leftcol is not rightcol and should_bind(rightcol, leftcol):
- binary.right = binds[rightcol] = sql.bindparam(None, None, type_=binary.left.type)
+ if rightcol in binds:
+ binary.right = binds[rightcol]
+ else:
+ binary.right = binds[rightcol] = sql.bindparam(None, None, type_=binary.left.type)
+
lazywhere = primaryjoin
if not secondaryjoin or not reverse_direction: