summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-02-28 18:51:39 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2015-02-28 18:51:39 -0500
commit149bcd108d9ab7b1a49ad728f72af1d3df7a7ecc (patch)
tree3ad732068bd35d90fd7ae1f0d14210048970464b
parent0a629e73297905462d4072f330d2389f5fc6d839 (diff)
downloadsqlalchemy-149bcd108d9ab7b1a49ad728f72af1d3df7a7ecc.tar.gz
- OK this version not working for polymorphic or bundles yet,
but for large loads it ties master, for many short loads it is slightly faster. if the code can be made clearer then it's a win
-rw-r--r--lib/sqlalchemy/orm/loading.py63
-rw-r--r--lib/sqlalchemy/orm/query.py71
-rw-r--r--lib/sqlalchemy/orm/strategies.py6
-rw-r--r--test/orm/test_loading.py2
4 files changed, 97 insertions, 45 deletions
diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py
index c4099a743..33b916fd4 100644
--- a/lib/sqlalchemy/orm/loading.py
+++ b/lib/sqlalchemy/orm/loading.py
@@ -42,12 +42,22 @@ def instances(query, cursor, context):
def filter_fn(row):
return tuple(fn(x) for x, fn in zip(row, filter_fns))
- if context._predefined_statement:
- for query_entity in query._entities:
- query_entity.setup_context(query, context, cursor)
-
try:
- (labels, process) = list(zip(*context.loaders))
+ if context._predefined_statement:
+ labels, process = list(zip(
+ *[
+ entity.create_row_processor(context, cursor, None)
+ for entity in query._entities
+ ]
+ ))
+ else:
+ labels, process = list(zip(
+ *[
+ entity.create_row_processor(context, cursor, loader)
+ for entity, loader
+ in zip(query._entities, context.loaders)
+ ]
+ ))
if not single_entity:
# TODO: this should be in context, so it can also be cached.
@@ -219,8 +229,9 @@ def load_on_ident(query, key,
def _instance_processor(
- mapper, props_toload, context, result, column_collection,
+ mapper, context, column_collection,
query_entity, path, adapter,
+ props_toload=None, result=None,
only_load_props=None, refresh_state=None,
polymorphic_discriminator=None,
_polymorphic_from=None):
@@ -231,7 +242,7 @@ def _instance_processor(
populators = collections.defaultdict(list)
- if result is None:
+ if props_toload:
for prop in props_toload:
prop.setup(
@@ -252,15 +263,6 @@ def _instance_processor(
identity_class = mapper._identity_class
- if result is not None:
- props = mapper._props.values()
- if only_load_props is not None:
- props = (p for p in props if p.key in only_load_props)
-
- for prop in props:
- prop.create_row_processor(
- result, context, path, mapper, adapter, populators)
-
propagate_options = context.propagate_options
if propagate_options:
load_path = context.query._current_path + path \
@@ -308,7 +310,7 @@ def _instance_processor(
# session, or we have to create a new one
identitykey = (
identity_class,
- tuple(row[col] for col in pk_cols)
+ tuple([row[col] for col in pk_cols])
)
instance = session_identity_map.get(identitykey)
@@ -400,6 +402,31 @@ def _instance_processor(
return instance
+ if result is not None:
+ props = mapper._props.values()
+ if only_load_props is not None:
+ props = (p for p in props if p.key in only_load_props)
+
+ for prop in props:
+ prop.create_row_processor(
+ result,
+ context, path, mapper, adapter, populators)
+ return _instance
+
+ def setup_result(result):
+ if context.outer_adapter:
+ populators["quick"] = [
+ (key, result._getter(context.outer_adapter.columns[col]))
+ for key, col in populators["quick"]
+ ]
+ else:
+ populators["quick"] = [
+ (key, result._getter(col)) for key, col in populators["quick"]
+ ]
+ return _instance
+
+ return setup_result
+
if load_is_polymorphic and not _polymorphic_from and not refresh_state:
# if we are doing polymorphic, dispatch to a different _instance()
# method specific to the subclass mapper
@@ -407,7 +434,7 @@ def _instance_processor(
_instance, context, mapper, query_entity, path,
polymorphic_discriminator, adapter)
- return _instance
+ #return _instance
def _populate_full(
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index 8988cac1b..01fd26827 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -3261,22 +3261,21 @@ class _MapperEntity(_QueryEntity):
return ret
- def setup_context(self, query, context, result=None):
+ def setup_context(self, query, context):
adapter = self._get_entity_clauses(query, context)
- if result is None:
- context.froms += (self.selectable,)
+ context.froms += (self.selectable,)
- if context.order_by is False and self.mapper.order_by:
- context.order_by = self.mapper.order_by
+ if context.order_by is False and self.mapper.order_by:
+ context.order_by = self.mapper.order_by
- # apply adaptation to the mapper's order_by if needed.
- if adapter:
- context.order_by = adapter.adapt_list(
- util.to_list(
- context.order_by
- )
+ # apply adaptation to the mapper's order_by if needed.
+ if adapter:
+ context.order_by = adapter.adapt_list(
+ util.to_list(
+ context.order_by
)
+ )
if self._with_polymorphic:
poly_properties = self.mapper._iterate_polymorphic_properties(
@@ -3298,19 +3297,45 @@ class _MapperEntity(_QueryEntity):
_instance = loading._instance_processor(
self.mapper,
- props_toload,
context,
- result,
context.primary_columns,
self,
self.path,
adapter,
+ props_toload=props_toload,
+ only_load_props=only_load_props,
+ refresh_state=refresh_state,
+ polymorphic_discriminator=self._polymorphic_discriminator
+ )
+
+ context.loaders.append(_instance)
+
+ def create_row_processor(self, context, result, loader):
+ if loader is not None:
+ return self._label_name, loader(result)
+
+ adapter = self._get_entity_clauses(context.query, context)
+
+ if context.query._primary_entity is self:
+ only_load_props = context.query._only_load_props
+ refresh_state = context.refresh_state
+ else:
+ only_load_props = refresh_state = None
+
+ _instance = loading._instance_processor(
+ self.mapper,
+ context,
+ context.primary_columns,
+ self,
+ self.path,
+ adapter,
+ result=result,
only_load_props=only_load_props,
refresh_state=refresh_state,
polymorphic_discriminator=self._polymorphic_discriminator
)
- context.loaders.append((self._label_name, _instance))
+ return self._label_name, _instance
def __str__(self):
return str(self.mapper)
@@ -3486,12 +3511,12 @@ class _BundleEntity(_QueryEntity):
for ent in self._entities:
ent.setup_entity(ext_info, aliased_adapter)
- def setup_context(self, query, context, result=None, loaders=None):
+ def setup_context(self, query, context, loaders=None):
our_loaders = []
for ent in self._entities:
ent.setup_context(
- query, context, result=result, loaders=our_loaders)
+ query, context, loaders=our_loaders)
labels, procs = zip(
*our_loaders
@@ -3635,17 +3660,21 @@ class _ColumnEntity(_QueryEntity):
def _resolve_expr_against_query_aliases(self, query, expr, context):
return query._adapt_clause(expr, False, True)
- def setup_context(self, query, context, result=None, loaders=None):
+ def setup_context(self, query, context, loaders=None):
column = self._resolve_expr_against_query_aliases(
query, self.column, context)
context.froms += tuple(self.froms)
context.primary_columns.append(column)
+ context.loaders.append(column)
- getter = operator.itemgetter(column)
- if loaders is not None:
- loaders.append((self._label_name, getter))
+ def create_row_processor(self, context, result, loader):
+ if loader is None:
+ column = self._resolve_expr_against_query_aliases(
+ context.query, self.column, context)
else:
- context.loaders.append((self._label_name, getter))
+ column = loader
+ getter = result._getter(column)
+ return self._label_name, getter
def __str__(self):
return str(self.column)
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 41f678955..a3885d3e0 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -149,12 +149,8 @@ class ColumnLoader(LoaderStrategy):
# should be added here so that we need not bother
# querying out every column.
- # TODO: wrong. we are again fetching by column and we are
- # not applying context.outer_adapter if we're in the primary
- # collection. Also, context.outer_adapter
- # isn't even set up yet. So again, we can't do this.
populators["quick"].append(
- (self.key, operator.itemgetter(self.columns[0]))
+ (self.key, self.columns[0])
)
def create_row_processor(
diff --git a/test/orm/test_loading.py b/test/orm/test_loading.py
index bfc1ad0c8..627a181ad 100644
--- a/test/orm/test_loading.py
+++ b/test/orm/test_loading.py
@@ -36,7 +36,7 @@ class InstancesTest(_fixtures.FixtureTest):
)
assert cursor.close.called, "Cursor wasn't closed"
- def test_query_load_entity(self):
+ def test_query_load_entity_one(self):
User = self.classes.User
s = Session()