From 4cf26a9e1bafdd4dfd849d51660be097ad7f7b86 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Fri, 18 Apr 2008 14:49:21 +0000 Subject: [PATCH] - restored usage of append_result() extension method for primary query rows, when the extension is present and only a single- entity result is being returned. --- CHANGES | 4 ++++ lib/sqlalchemy/orm/mapper.py | 2 +- lib/sqlalchemy/orm/query.py | 35 ++++++++++++++++++++++++----------- test/orm/mapper.py | 17 +++++++++++------ 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/CHANGES b/CHANGES index 8b6d86c062..3b4f15ee05 100644 --- a/CHANGES +++ b/CHANGES @@ -29,6 +29,10 @@ CHANGES class, not the mapped selectable, as the source of column attributes - so a warning is still issued. + - restored usage of append_result() extension method for primary + query rows, when the extension is present and only a single- + entity result is being returned. + - sql - Added COLLATE support via the .collate() expression operator and collate(, ) sql diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 5508b5c8e3..8fd26acf19 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -1442,7 +1442,7 @@ class Mapper(object): if 'populate_instance' not in extension.methods or extension.populate_instance(self, context, row, instance, only_load_props=attrs, instancekey=identitykey, isnew=isnew) is EXT_CONTINUE: self.populate_instance(context, instance, row, only_load_props=attrs, instancekey=identitykey, isnew=isnew) - + if result is not None and ('append_result' not in extension.methods or extension.append_result(self, context, row, instance, result, instancekey=identitykey, isnew=isnew) is EXT_CONTINUE): result.append(instance) diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index 880ff6d551..e4dadc62fc 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -954,16 +954,17 @@ class Query(object): if getattr(self, '_no_filters', False): filter = None - as_instances = False + single_entity = custom_rows = False else: - as_instances = isinstance(entities[0], _PrimaryMapperEntity) and len(entities) == 1 - - if as_instances: + single_entity = isinstance(entities[0], _PrimaryMapperEntity) and len(entities) == 1 + custom_rows = single_entity and 'append_result' in context.extension.methods + + if single_entity: filter = util.OrderedIdentitySet else: filter = util.OrderedSet - process = [query_entity.row_processor(self, context) for query_entity in entities] + process = [query_entity.row_processor(self, context, single_entity) for query_entity in entities] while True: context.progress = util.Set() @@ -975,8 +976,12 @@ class Query(object): return else: fetch = cursor.fetchall() - - if as_instances: + + if custom_rows: + rows = [] + for row in fetch: + process[0](context, row, rows) + elif single_entity: rows = [process[0](context, row) for row in fetch] else: rows = [tuple([proc(context, row) for proc in process]) for row in fetch] @@ -1502,7 +1507,7 @@ class _MapperEntity(_QueryEntity): else: return None - def row_processor(self, query, context): + def row_processor(self, query, context, single_entity): clauses = self._get_entity_clauses(query) if clauses: def proc(context, row): @@ -1524,8 +1529,15 @@ class _MapperEntity(_QueryEntity): class _PrimaryMapperEntity(_MapperEntity): """entity column corresponding to the 'primary' (first) mapped ORM instance.""" - def row_processor(self, query, context): - if context.row_adapter: + def row_processor(self, query, context, single_entity): + if single_entity and 'append_result' in context.extension.methods: + def main(context, row, result): + if context.row_adapter: + row = context.row_adapter(row) + self.mapper._instance(context, row, result, + extension=context.extension, only_load_props=context.only_load_props, refresh_instance=context.refresh_instance + ) + elif context.row_adapter: def main(context, row): return self.mapper._instance(context, context.row_adapter(row), None, extension=context.extension, only_load_props=context.only_load_props, refresh_instance=context.refresh_instance @@ -1535,6 +1547,7 @@ class _PrimaryMapperEntity(_MapperEntity): return self.mapper._instance(context, row, None, extension=context.extension, only_load_props=context.only_load_props, refresh_instance=context.refresh_instance ) + return main def setup_context(self, query, context): @@ -1608,7 +1621,7 @@ class _ColumnEntity(_QueryEntity): context.attributes[('_ColumnEntity', expr)] = ret = Adapter().traverse(expr, clone=True) return ret - def row_processor(self, query, context): + def row_processor(self, query, context, single_entity): column = self.__resolve_expr_against_query_aliases(query, self.column, context) def proc(context, row): return row[column] diff --git a/test/orm/mapper.py b/test/orm/mapper.py index b99e1fdda1..2024cbf6d7 100644 --- a/test/orm/mapper.py +++ b/test/orm/mapper.py @@ -1407,8 +1407,10 @@ class MapperExtensionTest(TestBase): sess.flush() sess.delete(u) sess.flush() - self.assertEquals(methods, ['before_insert', 'after_insert', 'load', 'translate_row', 'populate_instance', 'get', - 'translate_row', 'create_instance', 'populate_instance', 'before_update', 'after_update', 'before_delete', 'after_delete']) + self.assertEquals(methods, + ['before_insert', 'after_insert', 'load', 'translate_row', 'populate_instance', 'append_result', 'get', 'translate_row', + 'create_instance', 'populate_instance', 'append_result', 'before_update', 'after_update', 'before_delete', 'after_delete'] + ) def test_inheritance(self): # test using inheritance @@ -1429,8 +1431,9 @@ class MapperExtensionTest(TestBase): sess.flush() sess.delete(am) sess.flush() - self.assertEquals(methods, ['before_insert', 'after_insert', 'load', 'translate_row', 'populate_instance', 'get', - 'translate_row', 'create_instance', 'populate_instance', 'before_update', 'after_update', 'before_delete', 'after_delete']) + self.assertEquals(methods, + ['before_insert', 'after_insert', 'load', 'translate_row', 'populate_instance', 'append_result', 'get', + 'translate_row', 'create_instance', 'populate_instance', 'append_result', 'before_update', 'after_update', 'before_delete', 'after_delete']) def test_after_with_no_changes(self): # test that after_update is called even if no cols were updated @@ -1474,8 +1477,10 @@ class MapperExtensionTest(TestBase): sess.flush() sess.delete(am) sess.flush() - self.assertEquals(methods, ['before_insert', 'after_insert', 'load', 'translate_row', 'populate_instance', 'get', - 'translate_row', 'create_instance', 'populate_instance', 'before_update', 'after_update', 'before_delete', 'after_delete']) + self.assertEquals(methods, + ['before_insert', 'after_insert', 'load', 'translate_row', 'populate_instance', 'append_result', 'get', 'translate_row', + 'create_instance', 'populate_instance', 'append_result', 'before_update', 'after_update', 'before_delete', 'after_delete'] + ) class RequirementsTest(TestBase, AssertsExecutionResults): """Tests the contract for user classes.""" -- 2.47.3