Skip to content

fix: clamp count() at 0 when offset exceeds total#2208

Open
koriyoshi2041 wants to merge 1 commit into
tortoise:developfrom
koriyoshi2041:fix/count-negative-offset
Open

fix: clamp count() at 0 when offset exceeds total#2208
koriyoshi2041 wants to merge 1 commit into
tortoise:developfrom
koriyoshi2041:fix/count-negative-offset

Conversation

@koriyoshi2041
Copy link
Copy Markdown

Description

QuerySet.count() returns a negative number when offset() is larger than the total row count.

COUNT(*) ignores LIMIT/OFFSET, so CountQuery applies the offset in Python by subtracting it (tortoise/queryset.py):

count = list(dict(result[0]).values())[0] - self._offset

When offset > total, this goes negative. For example, with 5 rows:

await Item.all().offset(100).count()        # -> -95
len(await Item.all().offset(100))           # ->  0   (what SQL LIMIT/OFFSET actually returns)

The fix clamps the result at 0, matching the row count the equivalent query would actually return.

Motivation and Context

A count should never be negative; callers using .offset(...).count() (e.g. for pagination "remaining" math) get a nonsensical value.

How Has This Been Tested

Added test_offset_count_beyond_total in tests/test_queryset.py: with the 30-row IntFields fixture, offset(100).count() must equal 0 and match len(await ...offset(100)). It fails before the fix (-70) and passes after. Added a CHANGELOG.rst entry under 1.1.8 → Fixed.

COUNT(*) ignores LIMIT/OFFSET, so CountQuery applies the offset in Python by
subtracting it. When the offset is greater than the total row count the
subtraction went negative (e.g. .offset(100).count() returned -95 for 5 rows),
whereas the equivalent SQL LIMIT/OFFSET returns 0 rows. Clamp the result at 0.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant