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(<collation>)
expression operator and collate(<expr>, <collation>) sql
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)
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()
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]
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):
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
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):
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]
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
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
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."""