inheriting target, when used in the context of
prop.of_type(..).any()/has(), as well as
query.join(prop.of_type(...)).
-
+
+ - query.join() raises an error when the target of the join
+ doesn't match the property-based attribute - while it's
+ unlikely anyone is doing this, the SQLAlchemy author was
+ guilty of this particular loosey-goosey behavior.
+
- Fixed bug when using weak_instance_map=False where modified
events would not be intercepted for a flush(). [ticket:1272]
right_entity = None
for arg1 in util.to_list(keys):
- prop = None
aliased_entity = False
alias_criterion = False
left_entity = right_entity
- right_entity = right_mapper = None
+ prop = of_type = right_entity = right_mapper = None
if isinstance(arg1, tuple):
arg1, arg2 = arg1
descriptor, prop = _entity_descriptor(left_entity, onclause)
right_mapper = prop.mapper
+
if not right_entity:
right_entity = right_mapper
elif onclause is None:
raise sa_exc.InvalidRequestError("Could not find a FROM clause to join from")
mp, right_selectable, is_aliased_class = _entity_info(right_entity)
-
+
+ if mp is not None and right_mapper is not None and not mp.common_parent(right_mapper):
+ raise sa_exc.InvalidRequestError(
+ "Join target %s does not correspond to the right side of join condition %s" % (right_entity, onclause)
+ )
+
if not right_mapper and mp:
right_mapper = mp
if prop.secondary:
self.__currenttables.add(prop.secondary)
self.__currenttables.add(prop.table)
-
- if not right_entity:
+
+ if of_type:
+ right_entity = of_type
+ else:
right_entity = prop.mapper
if alias_criterion:
[]
)
+ def test_backwards_join(self):
+ # a more controversial feature. join from
+ # User->Address, but the onclause is Address.user.
+
+ sess = create_session()
+
+ self.assertEquals(
+ sess.query(User).join(Address.user).filter(Address.email_address=='ed@wood.com').all(),
+ [User(id=8,name=u'ed')]
+ )
+
+ # its actually not so controversial if you view it in terms
+ # of multiple entities.
+ self.assertEquals(
+ sess.query(User, Address).join(Address.user).filter(Address.email_address=='ed@wood.com').all(),
+ [(User(id=8,name=u'ed'), Address(email_address='ed@wood.com'))]
+ )
+
+ # this was the controversial part. now, raise an error if the feature is abused.
+ # before the error raise was added, this would silently work.....
+ self.assertRaises(
+ sa_exc.InvalidRequestError,
+ sess.query(User).join, (Address, Address.user),
+ )
+
+ # but this one would silently fail
+ adalias = aliased(Address)
+ self.assertRaises(
+ sa_exc.InvalidRequestError,
+ sess.query(User).join, (adalias, Address.user),
+ )
+
def test_multiple_with_aliases(self):
sess = create_session()