diff options
Diffstat (limited to 'lib/sqlalchemy/orm')
| -rw-r--r-- | lib/sqlalchemy/orm/loading.py | 48 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/persistence.py | 4 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/query.py | 15 |
4 files changed, 38 insertions, 31 deletions
diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py index 617f027d9..193980e6c 100644 --- a/lib/sqlalchemy/orm/loading.py +++ b/lib/sqlalchemy/orm/loading.py @@ -28,6 +28,7 @@ from .util import aliased from .util import state_str from .. import exc as sa_exc from .. import util +from ..engine import result_tuple from ..sql import util as sql_util @@ -56,7 +57,7 @@ def instances(query, cursor, context): ) try: - (process, labels) = list( + (process, labels, extra) = list( zip( *[ query_entity.row_processor(query, context, cursor) @@ -66,7 +67,7 @@ def instances(query, cursor, context): ) if not single_entity: - keyed_tuple = util.lightweight_named_tuple("result", labels) + keyed_tuple = result_tuple(labels, extra) while True: context.partials = {} @@ -138,7 +139,9 @@ def merge_result(querylib, query, iterator, load=True): ] result = [] keys = [ent._label_name for ent in query._entities] - keyed_tuple = util.lightweight_named_tuple("result", keys) + keyed_tuple = result_tuple( + keys, [ent.entities for ent in query._entities] + ) for row in iterator: newrow = list(row) for i in mapped_entities: @@ -190,7 +193,6 @@ def load_on_ident( query, key, refresh_state=None, with_for_update=None, only_load_props=None ): """Load the given identity key from the database.""" - if key is not None: ident = key[1] identity_token = key[2] @@ -452,10 +454,19 @@ def _instance_processor( instance_state = attributes.instance_state instance_dict = attributes.instance_dict session_id = context.session.hash_key - version_check = context.version_check runid = context.runid identity_token = context.identity_token + version_check = context.version_check + if version_check: + version_id_col = mapper.version_id_col + if version_id_col is not None: + if adapter: + version_id_col = adapter.columns[version_id_col] + version_id_getter = result._getter(version_id_col) + else: + version_id_getter = None + if not refresh_state and _polymorphic_from is not None: key = ("loader", path.path) if key in context.attributes and context.attributes[key].strategy == ( @@ -539,8 +550,10 @@ def _instance_processor( currentload = not isnew loaded_instance = False - if version_check and not currentload: - _validate_version_id(mapper, state, dict_, row, adapter) + if version_check and version_id_getter and not currentload: + _validate_version_id( + mapper, state, dict_, row, version_id_getter + ) else: # create a new instance @@ -667,7 +680,7 @@ def _instance_processor( def ensure_no_pk(row): identitykey = ( identity_class, - tuple([row[column] for column in pk_cols]), + tuple_getter(row), identity_token, ) if not is_not_primary_key(identitykey[1]): @@ -812,20 +825,11 @@ def _populate_partial( return to_load -def _validate_version_id(mapper, state, dict_, row, adapter): +def _validate_version_id(mapper, state, dict_, row, getter): - version_id_col = mapper.version_id_col - - if version_id_col is None: - return - - if adapter: - version_id_col = adapter.columns[version_id_col] - - if ( - mapper._get_state_attr_by_column(state, dict_, mapper.version_id_col) - != row[version_id_col] - ): + if mapper._get_state_attr_by_column( + state, dict_, mapper.version_id_col + ) != getter(row): raise orm_exc.StaleDataError( "Instance '%s' has version id '%s' which " "does not match database-loaded version id '%s'." @@ -834,7 +838,7 @@ def _validate_version_id(mapper, state, dict_, row, adapter): mapper._get_state_attr_by_column( state, dict_, mapper.version_id_col ), - row[version_id_col], + getter(row), ) ) diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 82e68fd07..b84d41260 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -2631,7 +2631,7 @@ class Mapper(sql_base.HasCacheKey, InspectionAttr): """Return an identity-map key for use in storing/retrieving an item from the identity map. - :param row: A :class:`.RowProxy` instance. The columns which are + :param row: A :class:`.Row` instance. The columns which are mapped by this :class:`.Mapper` should be locatable in the row, preferably via the :class:`.Column` object directly (as is the case when a :func:`.select` construct is executed), or via string names of diff --git a/lib/sqlalchemy/orm/persistence.py b/lib/sqlalchemy/orm/persistence.py index 31b8b0a20..95c5f8fa2 100644 --- a/lib/sqlalchemy/orm/persistence.py +++ b/lib/sqlalchemy/orm/persistence.py @@ -1522,7 +1522,7 @@ def _postfetch( if returning_cols: row = result.context.returned_defaults if row is not None: - for col in returning_cols: + for row_value, col in zip(row, returning_cols): # pk cols returned from insert are handled # distinctly, don't step on the values here if col.primary_key and result.context.isinsert: @@ -1534,7 +1534,7 @@ def _postfetch( # when using declarative w/ single table inheritance prop = mapper._columntoproperty.get(col) if prop: - dict_[prop.key] = row[col] + dict_[prop.key] = row_value if refresh_flush: load_evt_attrs.append(prop.key) diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index f19ec5673..d237aa3bf 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -47,6 +47,7 @@ from .. import inspection from .. import log from .. import sql from .. import util +from ..engine import result_tuple from ..sql import coercions from ..sql import expression from ..sql import roles @@ -56,6 +57,7 @@ from ..sql.base import _generative from ..sql.base import ColumnCollection from ..sql.base import Generative from ..sql.selectable import ForUpdateArg +from ..util import collections_abc __all__ = ["Query", "QueryContext", "aliased"] @@ -3320,7 +3322,7 @@ class Query(Generative): """ try: ret = self.one() - if not isinstance(ret, tuple): + if not isinstance(ret, collections_abc.Sequence): return ret return ret[0] except orm_exc.NoResultFound: @@ -4259,7 +4261,7 @@ class _MapperEntity(_QueryEntity): polymorphic_discriminator=self._polymorphic_discriminator, ) - return _instance, self._label_name + return _instance, self._label_name, self.entities def setup_context(self, query, context): adapter = self._get_entity_clauses(query, context) @@ -4414,7 +4416,7 @@ class Bundle(InspectionAttr): :ref:`bundles` - includes an example of subclassing. """ - keyed_tuple = util.lightweight_named_tuple("result", labels) + keyed_tuple = result_tuple(labels, [() for l in labels]) def proc(row): return keyed_tuple([proc(row) for proc in procs]) @@ -4517,7 +4519,7 @@ class _BundleEntity(_QueryEntity): ent.setup_context(query, context) def row_processor(self, query, context, result): - procs, labels = zip( + procs, labels, extra = zip( *[ ent.row_processor(query, context, result) for ent in self._entities @@ -4526,7 +4528,7 @@ class _BundleEntity(_QueryEntity): proc = self.bundle.create_row_processor(query, procs, labels) - return proc, self._label_name + return proc, self._label_name, () class _ColumnEntity(_QueryEntity): @@ -4675,7 +4677,8 @@ class _ColumnEntity(_QueryEntity): column = context.adapter.columns[column] getter = result._getter(column) - return getter, self._label_name + + return getter, self._label_name, (self.expr, self.column) def setup_context(self, query, context): column = query._adapt_clause(self.column, False, True) |
