diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2020-09-22 10:26:35 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2020-09-22 14:26:18 -0400 |
| commit | 96888aee7611c15532af2ae47e567f68c28b2474 (patch) | |
| tree | 88fa6819b09463a2b3b652c48ea9c3e370ba9443 /lib/sqlalchemy | |
| parent | e973fd5d5712b7212624b329015633fecfd1a25c (diff) | |
| download | sqlalchemy-96888aee7611c15532af2ae47e567f68c28b2474.tar.gz | |
Deprecate negative slice indexes
The "slice index" feature used by :class:`_orm.Query` as well as by the
dynamic relationship loader will no longer accept negative indexes in
SQLAlchemy 2.0. These operations do not work efficiently and load the
entire collection in, which is both surprising and undesirable. These
will warn in 1.4 unless the :paramref:`_orm.Session.future` flag is set in
which case they will raise IndexError.
Fixes: #5606
Change-Id: I5f5dcf984a8f41ab3d0e233ef7553e77fd99a771
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/dynamic.py | 4 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/query.py | 6 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/util.py | 20 |
3 files changed, 25 insertions, 5 deletions
diff --git a/lib/sqlalchemy/orm/dynamic.py b/lib/sqlalchemy/orm/dynamic.py index af67b4772..48161a256 100644 --- a/lib/sqlalchemy/orm/dynamic.py +++ b/lib/sqlalchemy/orm/dynamic.py @@ -510,7 +510,9 @@ class AppenderQuery(Generative): attributes.PASSIVE_NO_INITIALIZE, ).indexed(index) else: - return orm_util._getitem(self, index) + return orm_util._getitem( + self, index, allow_negative=not self.session.future + ) @_generative def limit(self, limit): diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index c6e6f6466..42987932d 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -2495,7 +2495,11 @@ class Query( self._compile_options += {"_enable_single_crit": False} def __getitem__(self, item): - return orm_util._getitem(self, item) + return orm_util._getitem( + self, + item, + allow_negative=not self.session or not self.session.future, + ) @_generative @_assertions(_no_statement_condition) diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py index 27b14d95b..c8d639e8c 100644 --- a/lib/sqlalchemy/orm/util.py +++ b/lib/sqlalchemy/orm/util.py @@ -1811,12 +1811,26 @@ def randomize_unitofwork(): ) = session.set = mapper.set = dependency.set = RandomSet -def _getitem(iterable_query, item): +def _getitem(iterable_query, item, allow_negative): """calculate __getitem__ in terms of an iterable query object that also has a slice() method. """ + def _no_negative_indexes(): + if not allow_negative: + raise IndexError( + "negative indexes are not accepted by SQL " + "index / slice operators" + ) + else: + util.warn_deprecated_20( + "Support for negative indexes for SQL index / slice operators " + "will be " + "removed in 2.0; these operators fetch the complete result " + "and do not work efficiently." + ) + if isinstance(item, slice): start, stop, step = util.decode_slice(item) @@ -1827,11 +1841,10 @@ def _getitem(iterable_query, item): ): return [] - # perhaps we should execute a count() here so that we - # can still use LIMIT/OFFSET ? elif (isinstance(start, int) and start < 0) or ( isinstance(stop, int) and stop < 0 ): + _no_negative_indexes() return list(iterable_query)[item] res = iterable_query.slice(start, stop) @@ -1841,6 +1854,7 @@ def _getitem(iterable_query, item): return list(res) else: if item == -1: + _no_negative_indexes() return list(iterable_query)[-1] else: return list(iterable_query[item : item + 1])[0] |
