fix: clamp count() at 0 when offset exceeds total#2208
Conversation
|
The One related edge case may be worth confirming while this code path is being adjusted: That seems to come from the existing limit clamp using a truthiness check: if self._limit and count > self._limit:
return self._limitSince await IntFields.all().limit(0).count() # currently 30
len(await IntFields.all().limit(0)) # 0This is not introduced by this PR, but it is the same |
COUNT(*) ignores LIMIT/OFFSET, so CountQuery applies them in Python. Two edge cases didn't match the limited query result: - offset greater than the total returned a negative number (e.g. .offset(100).count() == -95 for 5 rows) instead of 0. - limit(0) returned the full total instead of 0, because the limit clamp used a truthiness check (`if self._limit`) that skips 0. Clamp the offset subtraction at 0 and use `self._limit is not None` so an explicit limit(0) is honored.
e8d9c23 to
86f54ae
Compare
|
Good catch — fixed in the same change. |
|
Added in |
|
Please fix lint issue, you can try: |
|
Fixed, thanks. I ran Local checks now pass:
|
Description
QuerySet.count()returns a negative number whenoffset()is larger than the total row count.COUNT(*)ignoresLIMIT/OFFSET, soCountQueryapplies the offset in Python by subtracting it (tortoise/queryset.py):When
offset > total, this goes negative. For example, with 5 rows: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_totalintests/test_queryset.py: with the 30-rowIntFieldsfixture,offset(100).count()must equal0and matchlen(await ...offset(100)). It fails before the fix (-70) and passes after. Added aCHANGELOG.rstentry under 1.1.8 → Fixed.