summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-03-01 15:42:11 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2015-03-01 15:58:29 -0500
commit7c568bb4e887634872101789b2c2541557bc5df0 (patch)
treea6cada67e836ac277b796f9913562af9e2b7f929
parent0bda660d92d882e0cc6aa4cd72cad43ee021977f (diff)
downloadsqlalchemy-row_proc_integration_3.tar.gz
- turn on population fully. the change we have to make hererow_proc_integration_3
is to no longer attempt to locate deferred columns in the result. if a column is desired as undeferred, it needs to be stated as such.
-rw-r--r--lib/sqlalchemy/orm/loading.py17
-rw-r--r--lib/sqlalchemy/orm/properties.py2
-rw-r--r--lib/sqlalchemy/orm/strategies.py17
-rw-r--r--test/orm/test_deferred.py33
-rw-r--r--test/orm/test_eager_relations.py13
5 files changed, 52 insertions, 30 deletions
diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py
index d89358257..64c7e171c 100644
--- a/lib/sqlalchemy/orm/loading.py
+++ b/lib/sqlalchemy/orm/loading.py
@@ -292,19 +292,20 @@ def _instance_processor(
props = props.intersection(
mapper._props[k] for k in only_load_props)
- quick_populators = \
- path.get(
- context.attributes, "memoized_setups", _none_set)
+ quick_populators = path.get(
+ context.attributes, "memoized_setups", _none_set)
for prop in props:
- if False: #prop in quick_populators:
+ if prop in quick_populators:
# this is an inlined path just for column-based attributes.
col = quick_populators[prop]
if col is _DEFER_FOR_STATE:
populators["new"].append(
(prop.key, prop._deferred_column_loader))
-
elif col is _SET_DEFERRED_EXPIRED:
+ # note that in this path, we are no longer
+ # searching in the result to see if the column might
+ # be present in some unexpected way.
populators["expire"].append((prop.key, False))
else:
if adapter:
@@ -313,7 +314,11 @@ def _instance_processor(
if getter:
populators["quick"].append((prop.key, getter))
else:
- populators["expire"].append((prop.key, True))
+ # fall back to the ColumnProperty itself, which
+ # will iterate through all of its columns
+ # to see if one fits
+ prop.create_row_processor(
+ context, path, mapper, result, adapter, populators)
else:
prop.create_row_processor(
context, path, mapper, result, adapter, populators)
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index 93bfc4f12..31e9c7f3f 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -39,7 +39,7 @@ class ColumnProperty(StrategizedProperty):
'instrument', 'comparator_factory', 'descriptor', 'extension',
'active_history', 'expire_on_flush', 'info', 'doc',
'strategy_class', '_creation_order', '_is_polymorphic_discriminator',
- '_mapped_by_synonym', '_memoized_attr_deferred_loader')
+ '_mapped_by_synonym', '_deferred_loader')
def __init__(self, *columns, **kwargs):
"""Provide a column-level property for use with a Mapper.
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 532390927..a0b9bd31e 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -200,19 +200,12 @@ class DeferredColumnLoader(LoaderStrategy):
def create_row_processor(
self, context, path, loadopt,
mapper, result, adapter, populators):
- col = self.columns[0]
- if adapter:
- col = adapter.columns[col]
- # TODO: put a result-level contains here
- getter = result._getter(col)
- if getter:
- self.parent_property._get_strategy_by_cls(ColumnLoader).\
- create_row_processor(
- context, path, loadopt, mapper, result,
- adapter, populators)
-
- elif not self.is_class_level:
+ # this path currently does not check the result
+ # for the column; this is because in most cases we are
+ # working just with the setup_query() directive which does
+ # not support this, and the behavior here should be consistent.
+ if not self.is_class_level:
set_deferred_for_local_state = \
self.parent_property._deferred_column_loader
populators["new"].append((self.key, set_deferred_for_local_state))
diff --git a/test/orm/test_deferred.py b/test/orm/test_deferred.py
index 1b777b527..29087fdb8 100644
--- a/test/orm/test_deferred.py
+++ b/test/orm/test_deferred.py
@@ -341,7 +341,8 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest):
)
def test_locates_col(self):
- """Manually adding a column to the result undefers the column."""
+ """changed in 1.0 - we don't search for deferred cols in the result
+ now. """
orders, Order = self.tables.orders, self.classes.Order
@@ -350,18 +351,40 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest):
'description': deferred(orders.c.description)})
sess = create_session()
- o1 = sess.query(Order).order_by(Order.id).first()
+ o1 = (sess.query(Order).
+ order_by(Order.id).
+ add_column(orders.c.description).first())[0]
def go():
eq_(o1.description, 'order 1')
+ # prior to 1.0 we'd search in the result for this column
+ # self.sql_count_(0, go)
self.sql_count_(1, go)
+ def test_locates_col_rowproc_only(self):
+ """changed in 1.0 - we don't search for deferred cols in the result
+ now.
+
+ Because the loading for ORM Query and Query from a core select
+ is now split off, we test loading from a plain select()
+ separately.
+
+ """
+
+ orders, Order = self.tables.orders, self.classes.Order
+
+
+ mapper(Order, orders, properties={
+ 'description': deferred(orders.c.description)})
+
sess = create_session()
+ stmt = sa.select([Order]).order_by(Order.id)
o1 = (sess.query(Order).
- order_by(Order.id).
- add_column(orders.c.description).first())[0]
+ from_statement(stmt).all())[0]
def go():
eq_(o1.description, 'order 1')
- self.sql_count_(0, go)
+ # prior to 1.0 we'd search in the result for this column
+ # self.sql_count_(0, go)
+ self.sql_count_(1, go)
def test_deep_options(self):
users, items, order_items, Order, Item, User, orders = (self.tables.users,
diff --git a/test/orm/test_eager_relations.py b/test/orm/test_eager_relations.py
index 4c6d9bbe1..ea8db8fda 100644
--- a/test/orm/test_eager_relations.py
+++ b/test/orm/test_eager_relations.py
@@ -294,20 +294,21 @@ class EagerTest(_fixtures.FixtureTest, testing.AssertsCompiledSQL):
sess.expunge_all()
a = sess.query(Address).filter(Address.id == 1).all()[0]
+ # 1.0 change! we don't automatically undefer user_id here.
+ # if the user wants a column undeferred, add the option.
def go():
eq_(a.user_id, 7)
- # assert that the eager loader added 'user_id' to the row and deferred
- # loading of that col was disabled
- self.assert_sql_count(testing.db, go, 0)
+ # self.assert_sql_count(testing.db, go, 0)
+ self.assert_sql_count(testing.db, go, 1)
sess.expunge_all()
a = sess.query(Address).filter(Address.id == 1).first()
def go():
eq_(a.user_id, 7)
- # assert that the eager loader added 'user_id' to the row and deferred
- # loading of that col was disabled
- self.assert_sql_count(testing.db, go, 0)
+ # same, 1.0 doesn't check these
+ # self.assert_sql_count(testing.db, go, 0)
+ self.assert_sql_count(testing.db, go, 1)
# do the mapping in reverse
# (we would have just used an "addresses" backref but the test