summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/interfaces.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2010-03-22 20:15:50 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2010-03-22 20:15:50 -0400
commit0197a70343a7d6f4eb387bbd461e0624e2dc436b (patch)
tree1da79ee20f5910f40bf4490f2e5b84a1d25e2908 /lib/sqlalchemy/orm/interfaces.py
parentefcc9d782274ee1d5eb08855d50aaf627d76a073 (diff)
downloadsqlalchemy-0197a70343a7d6f4eb387bbd461e0624e2dc436b.tar.gz
- Fixed bug which affected all eagerload() and similar options
such that "remote" eager loads, i.e. eagerloads off of a lazy load such as query(A).options(eagerload(A.b, B.c)) wouldn't eagerload anything, but using eagerload("b.c") would work fine. - subquery eagerloading very close
Diffstat (limited to 'lib/sqlalchemy/orm/interfaces.py')
-rw-r--r--lib/sqlalchemy/orm/interfaces.py150
1 files changed, 80 insertions, 70 deletions
diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py
index c773e74f6..255b6b6fe 100644
--- a/lib/sqlalchemy/orm/interfaces.py
+++ b/lib/sqlalchemy/orm/interfaces.py
@@ -757,14 +757,35 @@ class PropertyOption(MapperOption):
self._process(query, False)
def _process(self, query, raiseerr):
- paths, mappers = self.__get_paths(query, raiseerr)
+ paths, mappers = self._get_paths(query, raiseerr)
if paths:
self.process_query_property(query, paths, mappers)
def process_query_property(self, query, paths, mappers):
pass
- def __find_entity(self, query, mapper, raiseerr):
+ def __getstate__(self):
+ d = self.__dict__.copy()
+ d['key'] = ret = []
+ for token in util.to_list(self.key):
+ if isinstance(token, PropComparator):
+ ret.append((token.mapper.class_, token.key))
+ else:
+ ret.append(token)
+ return d
+
+ def __setstate__(self, state):
+ ret = []
+ for key in state['key']:
+ if isinstance(key, tuple):
+ cls, propkey = key
+ ret.append(getattr(cls, propkey))
+ else:
+ ret.append(key)
+ state['key'] = tuple(ret)
+ self.__dict__ = state
+
+ def _find_entity(self, query, mapper, raiseerr):
from sqlalchemy.orm.util import _class_to_mapper, _is_aliased_class
if _is_aliased_class(mapper):
@@ -773,7 +794,7 @@ class PropertyOption(MapperOption):
else:
searchfor = _class_to_mapper(mapper)
isa = True
-
+
for ent in query._mapper_entities:
if searchfor is ent.path_entity or (
isa and
@@ -789,28 +810,7 @@ class PropertyOption(MapperOption):
else:
return None
- def __getstate__(self):
- d = self.__dict__.copy()
- d['key'] = ret = []
- for token in util.to_list(self.key):
- if isinstance(token, PropComparator):
- ret.append((token.mapper.class_, token.key))
- else:
- ret.append(token)
- return d
-
- def __setstate__(self, state):
- ret = []
- for key in state['key']:
- if isinstance(key, tuple):
- cls, propkey = key
- ret.append(getattr(cls, propkey))
- else:
- ret.append(key)
- state['key'] = tuple(ret)
- self.__dict__ = state
-
- def __get_paths(self, query, raiseerr):
+ def _get_paths(self, query, raiseerr):
path = None
entity = None
l = []
@@ -820,61 +820,71 @@ class PropertyOption(MapperOption):
# with an existing path
current_path = list(query._current_path)
- if self.mapper:
- entity = self.__find_entity(query, self.mapper, raiseerr)
- mapper = entity.mapper
- path_element = entity.path_entity
-
+ tokens = []
for key in util.to_list(self.key):
if isinstance(key, basestring):
- tokens = key.split('.')
+ tokens += key.split('.')
else:
- tokens = [key]
- for token in tokens:
- if isinstance(token, basestring):
- if not entity:
- entity = query._entity_zero()
- path_element = entity.path_entity
- mapper = entity.mapper
- mappers.append(mapper)
- prop = mapper.get_property(token, resolve_synonyms=True, raiseerr=raiseerr)
- key = token
- elif isinstance(token, PropComparator):
- prop = token.property
- if not entity:
- entity = self.__find_entity(query, token.parententity, raiseerr)
- if not entity:
- return [], []
- path_element = entity.path_entity
- mappers.append(prop.parent)
- key = prop.key
- else:
- raise sa_exc.ArgumentError("mapper option expects string key "
- "or list of attributes")
-
- if current_path and key == current_path[1]:
- current_path = current_path[2:]
- continue
+ tokens += [key]
+
+ for token in tokens:
+ if isinstance(token, basestring):
+ if not entity:
+ if current_path:
+ if current_path[1] == token:
+ current_path = current_path[2:]
+ continue
- if prop is None:
- return [], []
-
- path = build_path(path_element, prop.key, path)
- l.append(path)
- if getattr(token, '_of_type', None):
- path_element = mapper = token._of_type
- else:
- path_element = mapper = getattr(prop, 'mapper', None)
-
- if path_element:
- path_element = path_element
+ entity = query._entity_zero()
+ path_element = entity.path_entity
+ mapper = entity.mapper
+ mappers.append(mapper)
+ prop = mapper.get_property(
+ token,
+ resolve_synonyms=True,
+ raiseerr=raiseerr)
+ key = token
+ elif isinstance(token, PropComparator):
+ prop = token.property
+ if not entity:
+ if current_path:
+ if current_path[0:2] == [token.parententity, prop.key]:
+ current_path = current_path[2:]
+ continue
+
+ entity = self._find_entity(
+ query,
+ token.parententity,
+ raiseerr)
+ if not entity:
+ return [], []
+ path_element = entity.path_entity
+ mapper = entity.mapper
+ mappers.append(prop.parent)
+ key = prop.key
+ else:
+ raise sa_exc.ArgumentError("mapper option expects string key "
+ "or list of attributes")
+
+ if prop is None:
+ return [], []
+
+ path = build_path(path_element, prop.key, path)
+ l.append(path)
+ if getattr(token, '_of_type', None):
+ path_element = mapper = token._of_type
+ else:
+ path_element = mapper = getattr(prop, 'mapper', None)
+
+ if path_element:
+ path_element = path_element
# if current_path tokens remain, then
# we didn't have an exact path match.
if current_path:
return [], []
-
+
return l, mappers
class AttributeExtension(object):