diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-03-01 15:42:11 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-03-01 15:58:29 -0500 |
commit | 7c568bb4e887634872101789b2c2541557bc5df0 (patch) | |
tree | a6cada67e836ac277b796f9913562af9e2b7f929 | |
parent | 0bda660d92d882e0cc6aa4cd72cad43ee021977f (diff) | |
download | sqlalchemy-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.py | 17 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/properties.py | 2 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/strategies.py | 17 | ||||
-rw-r--r-- | test/orm/test_deferred.py | 33 | ||||
-rw-r--r-- | test/orm/test_eager_relations.py | 13 |
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 |