summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/query.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-06-20 19:28:29 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-06-20 19:28:29 -0400
commit3dd536ac06808adcf9c10707dbf2ebb6e3842be7 (patch)
treed102291da86021aa4584ef836dbb0471596c3eeb /lib/sqlalchemy/orm/query.py
parent40098941007ff3aa1593e834915c4042c1668dc2 (diff)
downloadsqlalchemy-3dd536ac06808adcf9c10707dbf2ebb6e3842be7.tar.gz
- [feature] The of_type() construct on attributes
now accepts aliased() class constructs as well as with_polymorphic constructs, and works with query.join(), any(), has(), and also eager loaders subqueryload(), joinedload(), contains_eager() [ticket:2438] [ticket:1106] - a rewrite of the query path system to use an object based approach for more succinct usage. the system has been designed carefully to not add an excessive method overhead. - [feature] select() features a correlate_except() method, auto correlates all selectables except those passed. Is needed here for the updated any()/has() functionality. - remove some old cruft from LoaderStrategy, init(),debug_callable() - use a namedtuple for _extended_entity_info. This method should become standard within the orm internals - some tweaks to the memory profile tests, number of runs can be customized to work around pysqlite's very annoying behavior - try to simplify PropertyOption._get_paths(), rename to _process_paths(), returns a single list now. overall works more completely as was needed for of_type() functionality
Diffstat (limited to 'lib/sqlalchemy/orm/query.py')
-rw-r--r--lib/sqlalchemy/orm/query.py68
1 files changed, 32 insertions, 36 deletions
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index 2c06063bc..987a77ba9 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -32,7 +32,7 @@ from sqlalchemy.orm import (
)
from sqlalchemy.orm.util import (
AliasedClass, ORMAdapter, _entity_descriptor, _entity_info,
- _extended_entity_info,
+ _extended_entity_info, PathRegistry,
_is_aliased_class, _is_mapped_class, _orm_columns, _orm_selectable,
join as orm_join,with_parent, _attr_as_key, aliased
)
@@ -53,6 +53,8 @@ def _generative(*assertions):
return self
return generate
+_path_registry = PathRegistry.root
+
class Query(object):
"""ORM-level SQL construction object.
@@ -88,7 +90,6 @@ class Query(object):
_invoke_all_eagers = True
_version_check = False
_autoflush = True
- _current_path = ()
_only_load_props = None
_refresh_state = None
_from_obj = ()
@@ -105,6 +106,8 @@ class Query(object):
_with_hints = ()
_enable_single_crit = True
+ _current_path = _path_registry
+
def __init__(self, entities, session=None):
self.session = session
self._polymorphic_adapters = {}
@@ -125,28 +128,25 @@ class Query(object):
for ent in entities:
for entity in ent.entities:
if entity not in d:
- mapper, selectable, \
- is_aliased_class, with_polymorphic_mappers, \
- with_polymorphic_discriminator = \
- _extended_entity_info(entity)
- if not is_aliased_class and mapper.with_polymorphic:
- if mapper.mapped_table not in \
+ ext_info = _extended_entity_info(entity)
+ if not ext_info.is_aliased_class and ext_info.mapper.with_polymorphic:
+ if ext_info.mapper.mapped_table not in \
self._polymorphic_adapters:
- self._mapper_loads_polymorphically_with(mapper,
+ self._mapper_loads_polymorphically_with(ext_info.mapper,
sql_util.ColumnAdapter(
- selectable,
- mapper._equivalent_columns))
+ ext_info.selectable,
+ ext_info.mapper._equivalent_columns))
aliased_adapter = None
- elif is_aliased_class:
+ elif ext_info.is_aliased_class:
aliased_adapter = sql_util.ColumnAdapter(
- selectable,
- mapper._equivalent_columns)
+ ext_info.selectable,
+ ext_info.mapper._equivalent_columns)
else:
aliased_adapter = None
- d[entity] = (mapper, aliased_adapter, selectable,
- is_aliased_class, with_polymorphic_mappers,
- with_polymorphic_discriminator)
+ d[entity] = (ext_info.mapper, aliased_adapter, ext_info.selectable,
+ ext_info.is_aliased_class, ext_info.with_polymorphic_mappers,
+ ext_info.with_polymorphic_discriminator)
ent.setup_entity(entity, *d[entity])
def _mapper_loads_polymorphically_with(self, mapper, adapter):
@@ -1251,7 +1251,7 @@ class Query(object):
def having(self, criterion):
"""apply a HAVING criterion to the query and return the
newly resulting :class:`.Query`.
-
+
:meth:`having` is used in conjunction with :meth:`group_by`.
HAVING criterion makes it possible to use filters on aggregate
@@ -1940,7 +1940,6 @@ class Query(object):
raise sa_exc.InvalidRequestError(
"Could not find a FROM clause to join from. "
"Tried joining to %s, but got: %s" % (right, ae))
-
self._from_obj = self._from_obj + (clause,)
def _reset_joinpoint(self):
@@ -2872,7 +2871,7 @@ class _MapperEntity(_QueryEntity):
query._entities.append(self)
self.entities = [entity]
- self.entity_zero = self.expr = entity
+ self.expr = entity
def setup_entity(self, entity, mapper, aliased_adapter,
from_obj, is_aliased_class,
@@ -2885,16 +2884,12 @@ class _MapperEntity(_QueryEntity):
self._with_polymorphic = with_polymorphic
self._polymorphic_discriminator = with_polymorphic_discriminator
if is_aliased_class:
- self.path_entity = self.entity_zero = entity
- self._path = (entity,)
+ self.entity_zero = entity
self._label_name = self.entity_zero._sa_label_name
- self._reduced_path = (self.path_entity, )
else:
- self.path_entity = mapper
- self._path = (mapper,)
- self._reduced_path = (mapper.base_mapper, )
self.entity_zero = mapper
self._label_name = self.mapper.class_.__name__
+ self.path = self.entity_zero._sa_path_registry
def set_with_polymorphic(self, query, cls_or_mappers,
selectable, polymorphic_on):
@@ -2929,10 +2924,13 @@ class _MapperEntity(_QueryEntity):
return self.entity_zero
def corresponds_to(self, entity):
- if _is_aliased_class(entity) or self.is_aliased_class:
- return entity is self.path_entity
+ entity_info = _extended_entity_info(entity)
+ if entity_info.is_aliased_class or self.is_aliased_class:
+ return entity is self.entity_zero \
+ or \
+ entity in self._with_polymorphic
else:
- return entity.common_parent(self.path_entity)
+ return entity.common_parent(self.entity_zero)
def adapt_to_selectable(self, query, sel):
query._entities.append(self)
@@ -2976,8 +2974,7 @@ class _MapperEntity(_QueryEntity):
if self.primary_entity:
_instance = self.mapper._instance_processor(
context,
- self._path,
- self._reduced_path,
+ self.path,
adapter,
only_load_props=query._only_load_props,
refresh_state=context.refresh_state,
@@ -2987,8 +2984,7 @@ class _MapperEntity(_QueryEntity):
else:
_instance = self.mapper._instance_processor(
context,
- self._path,
- self._reduced_path,
+ self.path,
adapter,
polymorphic_discriminator=
self._polymorphic_discriminator)
@@ -3024,8 +3020,7 @@ class _MapperEntity(_QueryEntity):
value.setup(
context,
self,
- self._path,
- self._reduced_path,
+ self.path,
adapter,
only_load_props=query._only_load_props,
column_collection=context.primary_columns
@@ -3211,7 +3206,8 @@ class QueryContext(object):
self.create_eager_joins = []
self.propagate_options = set(o for o in query._with_options if
o.propagate_to_loaders)
- self.attributes = query._attributes.copy()
+ self.attributes = self._attributes = query._attributes.copy()
+
class AliasOption(interfaces.MapperOption):