Merge lp:~adeuring/launchpad/bug-739052 into lp:launchpad
Status: | Merged |
---|---|
Approved by: | Abel Deuring |
Approved revision: | no longer in the source branch. |
Merged at revision: | 13587 |
Proposed branch: | lp:~adeuring/launchpad/bug-739052 |
Merge into: | lp:launchpad |
Diff against target: |
798 lines (+702/-16) 6 files modified
lib/canonical/launchpad/components/decoratedresultset.py (+23/-1) lib/canonical/launchpad/components/tests/decoratedresultset.txt (+16/-0) lib/canonical/launchpad/webapp/batching.py (+233/-2) lib/canonical/launchpad/webapp/interfaces.py (+6/-0) lib/canonical/launchpad/webapp/tests/test_batching.py (+423/-12) lib/canonical/launchpad/zcml/decoratedresultset.zcml (+1/-1) |
To merge this branch: | bzr merge lp:~adeuring/launchpad/bug-739052 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Robert Collins (community) | Approve | ||
Review via email: mp+69625@code.launchpad.net |
Commit message
[r=lifeless][no-qa] new class StormRangeFactory
Description of the change
This branch adds a class StormRangeFactory, which implements
the IRangeFactory interface. It works for Storm result sets,
and allows to retrieve batches as suggested by Jeroen some
months ago: Instead of an OFFSET clause it uses WHERE
expressions. The WHERE expressions are generated from the
sort expressions of the result set.
Limitations:
- The class works only for WHERE expressions like Person.id
or Desc(Person.id). In other words, it assumes that the
order expression is a Storm PropertyColumn. PropertyColumns
are Python descriptors, i.e., they provide the methods
__get__(), __set__(), __delete__(). They allow a usage like
Person.
where resultset[0] is an instance of class Person.
Sort expressions like
resultset
or
resultset
are not supported.
- The query must return instances of SQLBase-derived classes.
In other words, a query like
is not supported by StormRangeFactory. (A DecoratedResultSet
should be used in this case.)
The basic concept:
A StormRangeFactory is intended to be used by a
lazr.batchnavig
result set.
BatchNavigator calls range_factory.
parameters which describe how to retrieve the previous or next
batch. These values are use for "memo" parameter in URLs for
the previous/next batch.
StormRangeFacto
of the values of the sort columns of the first and last element
of the current batch.
This JSON representation is used in StormRangeFacto
to generate WHERE expressions.
This branch does a few no-nos:
- it imports PropertyColumn from storm.properties, but this
class does not appear in the module's __all__ list.
This import is not strictly necessary, but it makes the
detection possible usage problems much easier.
- it uses storm.store.
declared in IResultSet.
I suspected such problems when I started this branch; lifeless
suggested to start nevertheless -- we could submit patches to
Storm if this work turn out to be useful.
The new method DecoratedResult
with its security proxy treatment. This is necessary because
we use this class on both sides of the "security fence":
In model code as well as in browser code.
If a DecoratedResultSet is created in browser code, we need
to remove the security proxy of the plain result set in order
to call its method find(), but the new result set should
again be security proxied.
But if a DecoratedResultSet is created in model code, its
decorator can access "forbidden" attributes, so we cannot
store a proxied Storm ResultSet as self.result_set of the
new DecoratedResultSet generated by find(). An example is
the DecoratedResultSet returned by Bug.attachments: its
decorator (set_indexed_
attachment.
I "recycled" the file lib/canonical/
It did not run any doc tests, so I simply used it for the unit
tests.
tests:
./bin/test canonical -vvt canonical.
./bin/test canonical -vvt lib/canonical/
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/canonical
lib/canonical
lib/canonical
lib/canonical
./lib/canonical
1: narrative uses a moin header.
33: narrative uses a moin header.
56: narrative uses a moin header.
74: narrative uses a moin header.
82: narrative uses a moin header.
91: narrative uses a moin header.
99: narrative uses a moin header.
107: narrative uses a moin header.
121: narrative uses a moin header.
132: narrative uses a moin header.
139: narrative uses a moin header.
well... the diff for this branch is already 799 lines long, so I
did not remove the lint...
have a functional suggestion for you
currently you have some limits about requiring the thing being sorted on to be in the result set. find(resultset. _order_ by) will return those expressions (except for desc).
But resultset.
You could handle DecoratedResultSet by doing this: find(original_ find_expr + _order_ by_after_ stripping_ desc) and creating a lambda to strip the extra results off, then feed them back into the original decoratedresultset row / resultset callbacks.
resultset.
This could be done in a follow on patch of course.
The following are things I noted reading the patch, I don't think any are mandatory, but they are all pretty shallow so please give them your consideration.
DecoratedResultSet uses pep8 - foo_bar not fooBar, so you could follow its idiom there.
You can add find() to IResultSet via zcml magic if you want; personally I'd fixup storm directly (but after we have this working :)).
DateTimeJSONEncoder might want to live somewhere in the lazr.restful space I guess? What does lazr.restful do for datetime objects? I bet there is an existing encoder.
A decoratedresult set(decoratedre sultset( resultset) ) will barf atm - may want to loop in either the caller, or the get_plain_resultset method.
I would personally call getSortExpressions getOrderBy - given thats what it docstring says it does.
StormRangeFactory supports only sorting by
would be better english as
StormRangeFactory only supports sorting by
You may need expression, Desc):
300 + if isinstance(
301 + expression = expression.expr
302 + return expression < memo
303 + else:
304 + return expression > memo
to have >= instead of > - I'm not sure about this, but a collection sorted on two keys - say name, someint with rows ('foo', 1) ('foo', 2) ('foo', 3) ... would be a way to test this - make sure that pages work properly.
subclassing assertionerror - StormRangeFacto ryError( AssertionError) - is a bit ugly, better to subclass Exception directly
typo: Pytjon