Skip to content

Commit 3d18ff6

Browse files
committed
cqlengine: remove the negative indices slicing support in ModelQuerySet
1 parent af79000 commit 3d18ff6

4 files changed

Lines changed: 38 additions & 24 deletions

File tree

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Other
1515
-----
1616
* Cassandra 2.0 support removal (PYTHON-716)
1717
* cqlengine: disallow Counter create, save operations (PYTHON-497)
18+
* cqlengine: remove the negative indices slicing support in ModelQuerySet (PYTHON-875)
1819

1920
3.12.0
2021
======

cassandra/cqlengine/query.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -562,13 +562,15 @@ def __getitem__(self, s):
562562
if isinstance(s, slice):
563563
start = s.start if s.start else 0
564564

565-
# calculate the amount of results that need to be loaded
566-
end = s.stop
567-
if start < 0 or s.stop is None or s.stop < 0:
568-
end = self.count()
565+
# no support for negative indices
566+
if start < 0 or (s.stop is not None and s.stop < 0):
567+
raise ValueError("QuerySet slice indices must be positive")
569568

570569
try:
571-
self._fill_result_cache_to_idx(end)
570+
if s.stop:
571+
self._fill_result_cache_to_idx(s.stop)
572+
else:
573+
self._fill_result_cache()
572574
except StopIteration:
573575
pass
574576

@@ -579,10 +581,9 @@ def __getitem__(self, s):
579581
except (ValueError, TypeError):
580582
raise TypeError('QuerySet indices must be integers')
581583

582-
# Using negative indexing is costly since we have to execute a count()
584+
# no support for negative indices
583585
if s < 0:
584-
num_results = self.count()
585-
s += num_results
586+
raise ValueError("QuerySet indices must be positive")
586587

587588
try:
588589
self._fill_result_cache_to_idx(s)

docs/cqlengine/upgrade_guide.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ Upgrade Guide 3.x to 4.x
6464
v.rating_counter += 1
6565
v.update()
6666

67+
* ModelQuerySet support for negative slice indices has been removed due to the
68+
inefficiency and performance cost. The following code now raises an error::
69+
70+
Automobile.objects.all()[-10:]
71+
6772
Upgrade Guide cqlengine to cassandra.cqlengine
6873
==============================================
6974

tests/integration/cqlengine/query/test_queryset.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -653,11 +653,10 @@ def test_array_indexing_works_properly(self):
653653
assert q[i].attempt_id == expected_order[i]
654654

655655
@execute_count(1)
656-
def test_negative_indexing_works_properly(self):
656+
def test_negative_indexing_raises_error(self):
657657
q = TestModel.objects(test_id=0).order_by('attempt_id')
658-
expected_order = [0, 1, 2, 3]
659-
assert q[-1].attempt_id == expected_order[-1]
660-
assert q[-2].attempt_id == expected_order[-2]
658+
with self.assertRaises(ValueError):
659+
q[-1].attempt_id
661660

662661
@execute_count(1)
663662
def test_slicing_works_properly(self):
@@ -670,25 +669,33 @@ def test_slicing_works_properly(self):
670669
for model, expect in zip(q[0:3:2], expected_order[0:3:2]):
671670
self.assertEqual(model.attempt_id, expect)
672671

672+
for model, expect in zip(q[0:], expected_order):
673+
self.assertEqual(model.attempt_id, expect)
674+
673675
@execute_count(1)
674-
def test_negative_slicing(self):
676+
def test_negative_slicing_raises_error(self):
675677
q = TestModel.objects(test_id=0).order_by('attempt_id')
676-
expected_order = [0, 1, 2, 3]
677678

678-
for model, expect in zip(q[-3:], expected_order[-3:]):
679-
self.assertEqual(model.attempt_id, expect)
679+
with self.assertRaises(ValueError):
680+
q[-1:]
680681

681-
for model, expect in zip(q[:-1], expected_order[:-1]):
682-
self.assertEqual(model.attempt_id, expect)
682+
with self.assertRaises(ValueError):
683+
q[:-1]
683684

684-
for model, expect in zip(q[1:-1], expected_order[1:-1]):
685-
self.assertEqual(model.attempt_id, expect)
685+
with self.assertRaises(ValueError):
686+
q[1:-1]
686687

687-
for model, expect in zip(q[-3:-1], expected_order[-3:-1]):
688-
self.assertEqual(model.attempt_id, expect)
688+
with self.assertRaises(ValueError):
689+
q[-1:-1]
689690

690-
for model, expect in zip(q[-3:-1:2], expected_order[-3:-1:2]):
691-
self.assertEqual(model.attempt_id, expect)
691+
with self.assertRaises(ValueError):
692+
q[-1:1]
693+
694+
with self.assertRaises(ValueError):
695+
q[-1:4:2]
696+
697+
with self.assertRaises(ValueError):
698+
q[4:-1:2]
692699

693700

694701
class TestQuerySetValidation(BaseQuerySetUsage):

0 commit comments

Comments
 (0)