Merge lp:~adeuring/lazr.batchnavigator/lazr.batchnavigator-no-start-param-for-first-last-url into lp:lazr.batchnavigator
Status: | Merged |
---|---|
Merged at revision: | 50 |
Proposed branch: | lp:~adeuring/lazr.batchnavigator/lazr.batchnavigator-no-start-param-for-first-last-url |
Merge into: | lp:lazr.batchnavigator |
Diff against target: |
241 lines (+118/-18) 5 files modified
src/lazr/batchnavigator/_batchnavigator.py (+2/-2) src/lazr/batchnavigator/tests/test_batchnavigator.py (+17/-0) src/lazr/batchnavigator/tests/test_z3batching.py (+60/-8) src/lazr/batchnavigator/z3batching/batch.py (+33/-8) src/lazr/batchnavigator/z3batching/interfaces.py (+6/-0) |
To merge this branch: | bzr merge lp:~adeuring/lazr.batchnavigator/lazr.batchnavigator-no-start-param-for-first-last-url |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Graham Binns (community) | code | Approve | |
Review via email: mp+74249@code.launchpad.net |
Description of the change
BatchNavigator.
use the parameter start to determine if a "real" URL is returned
or if an empty URL is returned.
This works mostly fine when BatchNavigator can use a
ListRangeFactory, but it can lead to some confusion when a
StormRangeFactory is used. And even with a ListRangeFactory it
is possible to manually change the URL so that firstBatchURL()
and lastBatchURL() return an empty string: Just visit any
batched Launchpad view, click on the "next" link and then change
the query parameter "start=N" to "start=0". The page displayed
for this URL still shows the second batch, because BatchNavigator
and ListRangeFactory use the query parameter "memo" instead of
"start" to determine what to display. But the the "first batch"
on the page is just grey text instead of a "real" link.
For StormRangeFactory, this becomes a more serious problem, for
at least two reasons:
1:
StormRangeFactory does need to know the exact length of the
result set, which allows us to avoid expensive calls of
ResultSet.count(); we can use estimates of the row count
instead. This makes expressions like
batch_start + batch_size > length_
unreliable.
2:
* A user visits the first page of a batched list and clicks
on the "next" link
* For some reason, the result set changes so that another
element appears at the start of the result set.
* When the user now clicks the "previous" link, a view
using StormRangeFactory will return that part of the result
set coming directly before the current batch. This means
that there another previous batch, starting with the newly
created element. But the parameter "start" will still be
zero, thus disabing the "first batch" link. (The text
"previous batch" will still be a proper link.)
(ListRangeFactory will return the first batch, now starting
with the new element)
The code changes are simple:
_Batch.prevBatch() and _Batch.nextBatch() already had all
the logic needed to reliably determine if the current batch
is the first/last batch. I moced this logic into two new
properties, _Batch.
While prevBatch() and nextBatch() return None if the current
batch is the first/last batch, firstBatch(
return a _Batch instance, and firstBatchURL(
determine if a real link or an empty string should be returned.
This decision was based to the value of batch.start, but is now
based on the the new properties.
I also noticed that an existing test did not test what it was
supposed to test -- this required a range factory which works
similar to StormRangeFactory, as described above. This test
is also about the behaviour of _Batch when the the result set
changes, as described above.)
Hi Abel,
Nice branch, just a few nitpicky things that need to be taken care of
before landing. r=me.
[1]
30 + def test_lastBatchU RL_not_ empty_for_ bogus_start_ value(self) : batchnav( start=9, batch=3, memo="6") (batchnav. lastBatchURL( ), start=9, batch=3, direction= 'backwards' ))
31 + # lastBatchURL() is correct even when the start parameter
32 + # is bogus.
33 + batchnav = sample_
34 + self.assertThat
35 + EqualsQuery(
36 +
Why is the start parameter bogus here? Is that explained elsewhere? If
not, I think this needs a comment to explain why start=9 is bogus for
the batchnav you've created.
[2]
41 + def test_firstBatch URL_does_ not_depend_ on_start_ parameter( self): batchnav( start=0, batch=3, memo='3') (batchnav. firstBatchURL( ), EqualsQuery( batch=3) )
42 + # nextBatchURL() is correct even when start has the (incorrect)
43 + # value 0.
44 + batchnav = sample_
45 + self.assertThat
Same again, really. If these tests were failing and I had to look at
them I wouldn't understand why the values you're passing are incorrect.
Explaining it here saves time down the road.
[3]
106 + def test_has_ next_batch_ _forwards_ with_memo_ not_at_ end(self) :
111 + def test_has_ next_batch_ _forwards_ with_memo_ at_end( self):
116 + def test_has_ next_batch_ _forwards_ without_ memo_not_ at_end( self):
120 + def test_has_ next_batch_ _forwards_ without_ memo_at_ end(self) :
124 + def test_has_ next_batch_ _backwards_ with_memo_ not_at_ end(self) :
129 + def test_has_ next_batch_ _backforwards_ with_memo_ at_end( self):
I know it's obvious to you what these mean, but the act of truncating
the method names to fit within our character limits has stripped them of
context for someone who has not to start with (i.e. me). I'd appreciate
even a short comment at the start of each test explaining the expected
behaviour.
[4]
166 + return ( forwards and len(self. sliced_ list) > self.size) or
167 + (self.range_
168 + (not self.range_forwards and self.range_memo != ''))
That which is concise is often hard to parse. How about:
if self.range_ forwards: sliced_ list) > self.size
return len(self.
else:
return self.range_memo != ''
to make it clearer to chumps like me?