diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-06-06 18:07:05 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-06-06 18:07:05 -0400 |
| commit | 862913567a2589b4ff456726e2a61c9d478f45e1 (patch) | |
| tree | cd71f017b1a197db3e155e3edb6ffa4f2c84a3eb /lib | |
| parent | 555f30d64c23558a13bb95c2c10cb8556b5b21ae (diff) | |
| parent | 28c3325c4e18d01d7e0403229b452c8fbc345b80 (diff) | |
| download | sqlalchemy-862913567a2589b4ff456726e2a61c9d478f45e1.tar.gz | |
Merge branch 'ticket_2587'
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/query.py | 10 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/strategies.py | 12 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/util.py | 20 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/util.py | 11 |
5 files changed, 36 insertions, 19 deletions
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 285d338de..7f14d83cb 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -1767,7 +1767,7 @@ class Mapper(_InspectionAttr): while stack: item = stack.popleft() descendants.append(item) - stack.extend(item._inheriting_mappers) + stack.extend(sorted(item._inheriting_mappers, key=lambda m: m.class_.__name__)) return util.WeakSequence(descendants) def polymorphic_iterator(self): diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index 39ed8d8bf..54f5d7393 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -1897,7 +1897,7 @@ class Query(object): ) if not need_adapter and (create_aliases or aliased_entity): - right = aliased(right) + right = aliased(right, flat=True) need_adapter = True # if an alias() of the right side was generated here, @@ -2671,6 +2671,11 @@ class Query(object): # "load from explicit FROMs" mode, # i.e. when select_from() or join() is used context.froms = list(context.from_clause) + # this would fix... + #import pdb + #pdb.set_trace() + #context.froms += tuple(context.from_clause) + else: # "load from discrete FROMs" mode, # i.e. when each _MappedEntity has its own FROM @@ -2922,8 +2927,10 @@ class _MapperEntity(_QueryEntity): return entity.common_parent(self.entity_zero) + #_adapted_selectable = None def adapt_to_selectable(self, query, sel): query._entities.append(self) + # self._adapted_selectable = sel def _get_entity_clauses(self, query, context): @@ -2985,6 +2992,7 @@ class _MapperEntity(_QueryEntity): def setup_context(self, query, context): adapter = self._get_entity_clauses(query, context) + #if self._adapted_selectable is None: context.froms += (self.selectable,) if context.order_by is False and self.mapper.order_by: diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index cabfb35b9..6394003b3 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -1060,6 +1060,14 @@ class JoinedLoader(AbstractRelationshipLoader): column_collection=add_to_collection, allow_innerjoin=allow_innerjoin) + if with_poly_info is not None and \ + None in set(context.secondary_columns): + raise sa_exc.InvalidRequestError( + "Detected unaliased columns when generating joined " + "load. Make sure to use aliased=True or flat=True " + "when using joined loading with with_polymorphic()." + ) + def _get_user_defined_adapter(self, context, entity, path, adapter, user_defined_adapter): @@ -1089,6 +1097,7 @@ class JoinedLoader(AbstractRelationshipLoader): to_adapt = with_poly_info.entity else: to_adapt = orm_util.AliasedClass(self.mapper, + flat=True, use_mapper_path=True) clauses = orm_util.ORMAdapter( to_adapt, @@ -1415,8 +1424,7 @@ class LoadEagerFromAliasOption(PropertyOption): "path_with_polymorphic") adapter = orm_util.ORMAdapter( with_poly_info.entity, - equivalents=prop.mapper._equivalent_columns, - adapt_required=True) + equivalents=prop.mapper._equivalent_columns) else: adapter = query._polymorphic_adapters.get(prop.mapper, None) paths[-1].set(query._attributes, diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py index c21e7eace..7ac3ac96a 100644 --- a/lib/sqlalchemy/orm/util.py +++ b/lib/sqlalchemy/orm/util.py @@ -223,8 +223,8 @@ class ORMAdapter(sql_util.ColumnAdapter): and the AliasedClass if any is referenced. """ - def __init__(self, entity, equivalents=None, - chain_to=None, adapt_required=False): + def __init__(self, entity, equivalents=None, adapt_required=False, + chain_to=None): info = inspection.inspect(entity) self.mapper = info.mapper @@ -493,7 +493,7 @@ class AliasedClass(object): """ def __init__(self, cls, alias=None, name=None, - flat=True, + flat=False, adapt_on_names=False, # TODO: None for default here? with_polymorphic_mappers=(), @@ -502,7 +502,8 @@ class AliasedClass(object): use_mapper_path=False): mapper = _class_to_mapper(cls) if alias is None: - alias = mapper._with_polymorphic_selectable.alias(name=name, flat=flat) + alias = mapper._with_polymorphic_selectable.alias( + name=name, flat=flat) self._aliased_insp = AliasedInsp( self, mapper, @@ -701,7 +702,7 @@ inspection._inspects(AliasedClass)(lambda target: target._aliased_insp) inspection._inspects(AliasedInsp)(lambda target: target) -def aliased(element, alias=None, name=None, adapt_on_names=False): +def aliased(element, alias=None, name=None, flat=False, adapt_on_names=False): """Produce an alias of the given element, usually an :class:`.AliasedClass` instance. @@ -775,13 +776,14 @@ def aliased(element, alias=None, name=None, adapt_on_names=False): raise sa_exc.ArgumentError( "adapt_on_names only applies to ORM elements" ) - return element.alias(name) + return element.alias(name, flat=flat) else: - return AliasedClass(element, alias=alias, + return AliasedClass(element, alias=alias, flat=flat, name=name, adapt_on_names=adapt_on_names) def with_polymorphic(base, classes, selectable=False, + flat=False, polymorphic_on=None, aliased=False, innerjoin=False, _use_mapper_path=False): """Produce an :class:`.AliasedClass` construct which specifies @@ -837,8 +839,8 @@ def with_polymorphic(base, classes, selectable=False, mappers, selectable = primary_mapper.\ _with_polymorphic_args(classes, selectable, innerjoin=innerjoin) - if aliased: - selectable = selectable.alias(flat=True) + if aliased or flat: + selectable = selectable.alias(flat=flat) return AliasedClass(base, selectable, with_polymorphic_mappers=mappers, diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py index 6f4d27e1b..4422705cd 100644 --- a/lib/sqlalchemy/sql/util.py +++ b/lib/sqlalchemy/sql/util.py @@ -905,12 +905,11 @@ class ColumnAdapter(ClauseAdapter): if isinstance(c, expression.Label): c = c.label(None) - # adapt_required indicates that if we got the same column - # back which we put in (i.e. it passed through), - # it's not correct. this is used by eagerloading which - # knows that all columns and expressions need to be adapted - # to a result row, and a "passthrough" is definitely targeting - # the wrong column. + # adapt_required used by eager loading to indicate that + # we don't trust a result row column that is not translated. + # this is to prevent a column from being interpreted as that + # of the child row in a self-referential scenario, see + # inheritance/test_basic.py->EagerTargetingTest.test_adapt_stringency if self.adapt_required and c is col: return None |
