summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-10-28 04:36:36 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-10-28 04:36:36 +0000
commit103c867cf38a36db076eb1a841548638cbca0336 (patch)
tree2ebbb52a90dd28711e40972b36d9078ff1248f74 /lib/sqlalchemy
parent0282dc2738bee95901ade0374679e10f9b494898 (diff)
downloadsqlalchemy-103c867cf38a36db076eb1a841548638cbca0336.tar.gz
- a little cleanup to deferred inheritance loading
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/orm/strategies.py64
1 files changed, 31 insertions, 33 deletions
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 757021cd0..1c1813311 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -16,6 +16,8 @@ from sqlalchemy.orm import util as mapperutil
class ColumnLoader(LoaderStrategy):
+ """Default column loader."""
+
def init(self):
super(ColumnLoader, self).init()
self.columns = self.parent_property.columns
@@ -82,16 +84,42 @@ class ColumnLoader(LoaderStrategy):
# our mapped column is not present in the row. check if we need to initialize a polymorphic
# row fetcher used by inheritance.
(hosted_mapper, needs_tables) = selectcontext.attributes.get(('polymorphic_fetch', mapper), (None, None))
+
if hosted_mapper is None:
return (None, None, None)
if hosted_mapper.polymorphic_fetch == 'deferred':
# 'deferred' polymorphic row fetcher, put a callable on the property.
+ # create a deferred column loader which will query the remaining not-yet-loaded tables in an inheritance load.
+ # the mapper for the object creates the WHERE criterion using the mapper who originally
+ # "hosted" the query and the list of tables which are unloaded between the "hosted" mapper
+ # and this mapper. (i.e. A->B->C, the query used mapper A. therefore will need B's and C's tables
+ # in the query).
+
+ # deferred loader strategy
+ strategy = self.parent_property._get_strategy(DeferredColumnLoader)
+
+ # full list of ColumnProperty objects to be loaded in the deferred fetch
+ props = [p for p in mapper.iterate_properties if isinstance(p.strategy, ColumnLoader) and p.columns[0].table in needs_tables]
+
+ # TODO: we are somewhat duplicating efforts from mapper._get_poly_select_loader
+ # and should look for ways to simplify.
+ cond, param_names = mapper._deferred_inheritance_condition(hosted_mapper, needs_tables)
+ statement = sql.select(needs_tables, cond, use_labels=True)
+ def create_statement(instance):
+ params = {}
+ for c in param_names:
+ params[c.name] = mapper.get_attr_by_column(instance, c)
+ return (statement, params)
+
def new_execute(instance, row, isnew, **flags):
if isnew:
- sessionlib.attribute_manager.init_instance_attribute(instance, self.key, callable_=self._get_deferred_inheritance_loader(instance, mapper, hosted_mapper, needs_tables))
+ loader = strategy.setup_loader(instance, props=props, create_statement=create_statement)
+ sessionlib.attribute_manager.init_instance_attribute(instance, self.key, callable_=loader)
+
if self._should_log_debug:
self.logger.debug("Returning deferred column fetcher for %s %s" % (mapper, self.key))
+
return (new_execute, None, None)
else:
# immediate polymorphic row fetcher. no processing needed for this row.
@@ -99,41 +127,11 @@ class ColumnLoader(LoaderStrategy):
self.logger.debug("Returning no column fetcher for %s %s" % (mapper, self.key))
return (None, None, None)
- def _get_deferred_inheritance_loader(self, instance, mapper, hosted_mapper, needs_tables):
- # create a deferred column loader which will query the remaining not-yet-loaded tables in an inheritance load.
- # the mapper for the object creates the WHERE criterion using the mapper who originally
- # "hosted" the query and the list of tables which are unloaded between the "hosted" mapper
- # and this mapper. (i.e. A->B->C, the query used mapper A. therefore will need B's and C's tables
- # in the query).
- def create_statement():
- # TODO: the SELECT statement here should be cached in the selectcontext. we are somewhat duplicating
- # efforts from mapper._get_poly_select_loader as well and should look
- # for ways to simplify.
- cond, param_names = mapper._deferred_inheritance_condition(hosted_mapper, needs_tables)
- statement = sql.select(needs_tables, cond, use_labels=True)
- params = {}
- for c in param_names:
- params[c.name] = mapper.get_attr_by_column(instance, c)
- return (statement, params)
-
- # install the create_statement() callable using the deferred loading strategy
- strategy = self.parent_property._get_strategy(DeferredColumnLoader)
-
- # assemble list of all ColumnProperties which will need to be loaded
- props = [p for p in mapper.iterate_properties if isinstance(p.strategy, ColumnLoader) and p.columns[0].table in needs_tables]
-
- # set the deferred loader on the instance attribute
- return strategy.setup_loader(instance, props=props, create_statement=create_statement)
-
ColumnLoader.logger = logging.class_logger(ColumnLoader)
class DeferredColumnLoader(LoaderStrategy):
- """Describes an object attribute that corresponds to a table
- column, which also will *lazy load* its value from the table.
-
- This is per-column lazy loading.
- """
+ """Deferred column loader, a per-column or per-column-group lazy loader."""
def create_row_processor(self, selectcontext, mapper, row):
if self.group is not None and selectcontext.attributes.get(('undefer', self.group), False):
@@ -207,7 +205,7 @@ class DeferredColumnLoader(LoaderStrategy):
params[param_map[primary_key].key] = ident[i]
statement = sql.select([p.columns[0] for p in group], clause, from_obj=[localparent.mapped_table], use_labels=True)
else:
- statement, params = create_statement()
+ statement, params = create_statement(instance)
# TODO: have the "fetch of one row" operation go through the same channels as a query._get()
# deferred load of several attributes should be a specialized case of a query refresh operation