summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/util.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2013-06-17 18:48:17 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2013-06-17 19:42:43 -0400
commit7f82168cb6b0f0e22d387ffeca1ae82f526c2f29 (patch)
tree1ef9195524e6de9fc1e49e07795398538ac20043 /lib/sqlalchemy/orm/util.py
parent42d58f8b6e67c01827f1eed283e23067bbdb848d (diff)
downloadsqlalchemy-7f82168cb6b0f0e22d387ffeca1ae82f526c2f29.tar.gz
- rework PropComparator.adapted() to be PropComparator.adapt_to_entity(),
passes in AliasedInsp and allows more flexibility. - rework the AliasedClass/AliasedInsp relationship so that AliasedInsp has all state and functionality. AliasedClass is just a facade. [ticket:2756]
Diffstat (limited to 'lib/sqlalchemy/orm/util.py')
-rw-r--r--lib/sqlalchemy/orm/util.py181
1 files changed, 100 insertions, 81 deletions
diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py
index ef9de760e..617ef6085 100644
--- a/lib/sqlalchemy/orm/util.py
+++ b/lib/sqlalchemy/orm/util.py
@@ -516,88 +516,32 @@ class AliasedClass(object):
if with_polymorphic_discriminator is not None
else mapper.polymorphic_on,
base_alias,
- use_mapper_path
+ use_mapper_path,
+ adapt_on_names
)
- self._setup(self._aliased_insp, adapt_on_names)
-
-
- def _setup(self, aliased_insp, adapt_on_names):
- self.__adapt_on_names = adapt_on_names
- mapper = aliased_insp.mapper
- alias = aliased_insp.selectable
- self.__target = mapper.class_
- self.__adapt_on_names = adapt_on_names
- self.__adapter = sql_util.ClauseAdapter(alias,
- equivalents=mapper._equivalent_columns,
- adapt_on_names=self.__adapt_on_names)
- for poly in aliased_insp.with_polymorphic_mappers:
- if poly is not mapper:
- setattr(self, poly.class_.__name__,
- AliasedClass(poly.class_, alias, base_alias=self,
- use_mapper_path=self._aliased_insp._use_mapper_path))
-
- self.__name__ = 'AliasedClass_%s' % self.__target.__name__
-
- def __getstate__(self):
- return {
- 'mapper': self._aliased_insp.mapper,
- 'alias': self._aliased_insp.selectable,
- 'name': self._aliased_insp.name,
- 'adapt_on_names': self.__adapt_on_names,
- 'with_polymorphic_mappers':
- self._aliased_insp.with_polymorphic_mappers,
- 'with_polymorphic_discriminator':
- self._aliased_insp.polymorphic_on,
- 'base_alias': self._aliased_insp._base_alias.entity,
- 'use_mapper_path': self._aliased_insp._use_mapper_path
- }
-
- def __setstate__(self, state):
- self._aliased_insp = AliasedInsp(
- self,
- state['mapper'],
- state['alias'],
- state['name'],
- state['with_polymorphic_mappers'],
- state['with_polymorphic_discriminator'],
- state['base_alias'],
- state['use_mapper_path']
- )
- self._setup(self._aliased_insp, state['adapt_on_names'])
-
- def __adapt_element(self, elem):
- return self.__adapter.traverse(elem).\
- _annotate({
- 'parententity': self,
- 'parentmapper': self._aliased_insp.mapper}
- )
-
- def __adapt_prop(self, existing, key):
- comparator = existing.comparator.adapted(self.__adapt_element)
- queryattr = attributes.QueryableAttribute(
- self, key,
- impl=existing.impl,
- parententity=self._aliased_insp,
- comparator=comparator)
- setattr(self, key, queryattr)
- return queryattr
+ self.__name__ = 'AliasedClass_%s' % mapper.class_.__name__
def __getattr__(self, key):
- for base in self.__target.__mro__:
- try:
- attr = object.__getattribute__(base, key)
- except AttributeError:
- continue
- else:
- break
+ try:
+ _aliased_insp = self.__dict__['_aliased_insp']
+ except KeyError:
+ raise AttributeError()
else:
- raise AttributeError(key)
+ for base in _aliased_insp._target.__mro__:
+ try:
+ attr = object.__getattribute__(base, key)
+ except AttributeError:
+ continue
+ else:
+ break
+ else:
+ raise AttributeError(key)
if isinstance(attr, attributes.QueryableAttribute):
- return self.__adapt_prop(attr, key)
+ return _aliased_insp._adapt_prop(attr, key)
elif hasattr(attr, 'func_code'):
- is_method = getattr(self.__target, key, None)
+ is_method = getattr(_aliased_insp._target, key, None)
if is_method and is_method.__self__ is not None:
return util.types.MethodType(attr.__func__, self, self)
else:
@@ -605,14 +549,14 @@ class AliasedClass(object):
elif hasattr(attr, '__get__'):
ret = attr.__get__(None, self)
if isinstance(ret, PropComparator):
- return ret.adapted(self.__adapt_element)
+ return ret.adapt_to_entity(_aliased_insp)
return ret
else:
return attr
def __repr__(self):
return '<AliasedClass at 0x%x; %s>' % (
- id(self), self.__target.__name__)
+ id(self), self._aliased_insp._target.__name__)
class AliasedInsp(_InspectionAttr):
@@ -653,19 +597,29 @@ class AliasedInsp(_InspectionAttr):
def __init__(self, entity, mapper, selectable, name,
with_polymorphic_mappers, polymorphic_on,
- _base_alias, _use_mapper_path):
+ _base_alias, _use_mapper_path, adapt_on_names):
self.entity = entity
self.mapper = mapper
self.selectable = selectable
self.name = name
self.with_polymorphic_mappers = with_polymorphic_mappers
self.polymorphic_on = polymorphic_on
-
- # a little dance to get serialization to work
- self._base_alias = _base_alias._aliased_insp if _base_alias \
- and _base_alias is not entity else self
+ self._base_alias = _base_alias or self
self._use_mapper_path = _use_mapper_path
+ self._adapter = sql_util.ClauseAdapter(selectable,
+ equivalents=mapper._equivalent_columns,
+ adapt_on_names=adapt_on_names)
+
+ self._adapt_on_names = adapt_on_names
+ self._target = mapper.class_
+
+ for poly in self.with_polymorphic_mappers:
+ if poly is not mapper:
+ setattr(self.entity, poly.class_.__name__,
+ AliasedClass(poly.class_, selectable, base_alias=self,
+ adapt_on_names=adapt_on_names,
+ use_mapper_path=_use_mapper_path))
is_aliased_class = True
"always returns True"
@@ -683,6 +637,52 @@ class AliasedInsp(_InspectionAttr):
else:
return PathRegistry.per_mapper(self)
+ def __getstate__(self):
+ return {
+ 'entity': self.entity,
+ 'mapper': self.mapper,
+ 'alias': self.selectable,
+ 'name': self.name,
+ 'adapt_on_names': self._adapt_on_names,
+ 'with_polymorphic_mappers':
+ self.with_polymorphic_mappers,
+ 'with_polymorphic_discriminator':
+ self.polymorphic_on,
+ 'base_alias': self._base_alias,
+ 'use_mapper_path': self._use_mapper_path
+ }
+
+ def __setstate__(self, state):
+ self.__init__(
+ state['entity'],
+ state['mapper'],
+ state['alias'],
+ state['name'],
+ state['with_polymorphic_mappers'],
+ state['with_polymorphic_discriminator'],
+ state['base_alias'],
+ state['use_mapper_path'],
+ state['adapt_on_names']
+ )
+
+ def _adapt_element(self, elem):
+ return self._adapter.traverse(elem).\
+ _annotate({
+ 'parententity': self.entity,
+ 'parentmapper': self.mapper}
+ )
+
+ def _adapt_prop(self, existing, key):
+ comparator = existing.comparator.adapt_to_entity(self)
+ queryattr = attributes.QueryableAttribute(
+ self.entity, key,
+ impl=existing.impl,
+ parententity=self,
+ comparator=comparator)
+ setattr(self.entity, key, queryattr)
+ return queryattr
+
+
def _entity_for_mapper(self, mapper):
self_poly = self.with_polymorphic_mappers
if mapper in self_poly:
@@ -692,6 +692,25 @@ class AliasedInsp(_InspectionAttr):
else:
assert False, "mapper %s doesn't correspond to %s" % (mapper, self)
+ def _adapt_element(self, elem):
+ return self._adapter.traverse(elem).\
+ _annotate({
+ 'parententity': self.entity,
+ 'parentmapper': self.mapper}
+ )
+
+ def _adapt_prop(self, existing, key):
+ comparator = existing.comparator.adapt_to_entity(self)
+ queryattr = attributes.QueryableAttribute(
+ self.entity, key,
+ impl=existing.impl,
+ parententity=self,
+ comparator=comparator)
+ setattr(self.entity, key, queryattr)
+ return queryattr
+
+
+
def __repr__(self):
return '<AliasedInsp at 0x%x; %s>' % (
id(self), self.class_.__name__)