launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #07138
[Merge] lp:~wgrant/launchpad/eliminate-prejoins-where-possible into lp:launchpad
William Grant has proposed merging lp:~wgrant/launchpad/eliminate-prejoins-where-possible into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #696167 in Launchpad itself: "duplicate milestones in advanced person's bug search"
https://bugs.launchpad.net/launchpad/+bug/696167
For more details, see:
https://code.launchpad.net/~wgrant/launchpad/eliminate-prejoins-where-possible/+merge/102254
This branch removes prejoin support from bugtasksearch. It was only used for two things (the milestone listing on https://launchpad.net/~/+bugs?advanced=1 and preloading the corresponding Bug for each BugTask), and makes BugTaskFlat integration unbelievably awful.
I replaced the milestone madness with a simple load_related. It's still terribly inefficient (loading every task related to the person, I mean what?), but it's better than it was. This also happens to fix bug #696167 by not being insane.
The Bug prejoin in search() itself is replaced with a load_related(). I also replaced all the other preloading in search() with load_related(), since load_related() is awesome unlike pretty much everything else in the codebase.
--
https://code.launchpad.net/~wgrant/launchpad/eliminate-prejoins-where-possible/+merge/102254
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/eliminate-prejoins-where-possible into lp:launchpad.
=== modified file 'lib/lp/bugs/browser/bugtask.py'
--- lib/lp/bugs/browser/bugtask.py 2012-04-03 06:14:09 +0000
+++ lib/lp/bugs/browser/bugtask.py 2012-04-17 08:56:23 +0000
@@ -3036,7 +3036,7 @@
return self._batch_navigator
def searchUnbatched(self, searchtext=None, context=None,
- extra_params=None, prejoins=[]):
+ extra_params=None):
"""Return a `SelectResults` object for the GET search criteria.
:param searchtext: Text that must occur in the bug report. If
@@ -3055,7 +3055,7 @@
searchtext=searchtext, extra_params=extra_params)
search_params.user = self.user
try:
- tasks = context.searchTasks(search_params, prejoins=prejoins)
+ tasks = context.searchTasks(search_params)
except ValueError as e:
self.request.response.addErrorNotification(str(e))
self.request.response.redirect(canonical_url(
=== modified file 'lib/lp/bugs/browser/person.py'
--- lib/lp/bugs/browser/person.py 2012-02-28 04:24:19 +0000
+++ lib/lp/bugs/browser/person.py 2012-04-17 08:56:23 +0000
@@ -21,7 +21,6 @@
from operator import itemgetter
import urllib
-from storm.expr import Join
from zope.component import getUtility
from zope.schema.vocabulary import getVocabularyRegistry
@@ -32,12 +31,12 @@
IBugTaskSet,
UNRESOLVED_BUGTASK_STATUSES,
)
-from lp.bugs.model.bugtask import BugTask
from lp.registry.interfaces.person import IPerson
from lp.registry.model.milestone import (
Milestone,
milestone_sort_key,
)
+from lp.services.database.bulk import load_related
from lp.services.feeds.browser import FeedsMixin
from lp.services.helpers import shortlist
from lp.services.propertycache import cachedproperty
@@ -142,12 +141,10 @@
def getMilestoneWidgetValues(self):
"""Return data used to render the milestone checkboxes."""
- prejoins = [
- (Milestone, Join(Milestone, BugTask.milestone == Milestone.id))]
- milestones = [
- bugtask.milestone
- for bugtask in self.searchUnbatched(prejoins=prejoins)]
- milestones = sorted(milestones, key=milestone_sort_key, reverse=True)
+ tasks = self.searchUnbatched()
+ milestones = sorted(
+ load_related(Milestone, tasks, ['milestoneID']),
+ key=milestone_sort_key, reverse=True)
return [
dict(title=milestone.title, value=milestone.id, checked=False)
for milestone in milestones]
@@ -363,7 +360,7 @@
view_name = '+assignedbugs'
def searchUnbatched(self, searchtext=None, context=None,
- extra_params=None, prejoins=[]):
+ extra_params=None):
"""Return the open bugs assigned to a person."""
if context is None:
context = self.context
@@ -375,8 +372,7 @@
extra_params['assignee'] = context
sup = super(PersonAssignedBugTaskSearchListingView, self)
- return sup.searchUnbatched(
- searchtext, context, extra_params, prejoins)
+ return sup.searchUnbatched(searchtext, context, extra_params)
def shouldShowAssigneeWidget(self):
"""Should the assignee widget be shown on the advanced search page?"""
@@ -421,7 +417,7 @@
page_title = 'Commented bugs'
def searchUnbatched(self, searchtext=None, context=None,
- extra_params=None, prejoins=[]):
+ extra_params=None):
"""Return the open bugs commented on by a person."""
if context is None:
context = self.context
@@ -433,8 +429,7 @@
extra_params['bug_commenter'] = context
sup = super(PersonCommentedBugTaskSearchListingView, self)
- return sup.searchUnbatched(
- searchtext, context, extra_params, prejoins)
+ return sup.searchUnbatched(searchtext, context, extra_params)
@property
def context_description(self):
@@ -468,7 +463,7 @@
page_title = 'Bugs affecting' # The context is added externally.
def searchUnbatched(self, searchtext=None, context=None,
- extra_params=None, prejoins=[]):
+ extra_params=None):
"""Return the open bugs assigned to a person."""
if context is None:
context = self.context
@@ -480,8 +475,7 @@
extra_params['affected_user'] = context
sup = super(PersonAffectingBugTaskSearchListingView, self)
- return sup.searchUnbatched(
- searchtext, context, extra_params, prejoins)
+ return sup.searchUnbatched(searchtext, context, extra_params)
def shouldShowAssigneeWidget(self):
"""Should the assignee widget be shown on the advanced search page?"""
@@ -527,7 +521,7 @@
page_title = 'Related bugs'
def searchUnbatched(self, searchtext=None, context=None,
- extra_params=None, prejoins=[]):
+ extra_params=None):
"""Return the open bugs related to a person.
:param extra_params: A dict that provides search params added to
@@ -557,8 +551,7 @@
commenter_params.bug_commenter = context
return context.searchTasks(
- assignee_params, subscriber_params, owner_params,
- commenter_params, prejoins=prejoins)
+ assignee_params, subscriber_params, owner_params, commenter_params)
@property
def context_description(self):
@@ -588,7 +581,7 @@
page_title = 'Reported bugs'
def searchUnbatched(self, searchtext=None, context=None,
- extra_params=None, prejoins=[]):
+ extra_params=None):
"""Return the bugs reported by a person."""
if context is None:
context = self.context
@@ -603,8 +596,7 @@
extra_params['bug_reporter'] = context
sup = super(PersonReportedBugTaskSearchListingView, self)
- return sup.searchUnbatched(
- searchtext, context, extra_params, prejoins)
+ return sup.searchUnbatched(searchtext, context, extra_params)
@property
def context_description(self):
@@ -646,7 +638,7 @@
view_name = '+subscribedbugs'
def searchUnbatched(self, searchtext=None, context=None,
- extra_params=None, prejoins=[]):
+ extra_params=None):
"""Return the bugs subscribed to by a person."""
if context is None:
context = self.context
@@ -658,8 +650,7 @@
extra_params['subscriber'] = context
sup = super(PersonSubscribedBugTaskSearchListingView, self)
- return sup.searchUnbatched(
- searchtext, context, extra_params, prejoins)
+ return sup.searchUnbatched(searchtext, context, extra_params)
def shouldShowTeamPortlet(self):
"""Should the team subscribed bugs portlet be shown?"""
=== modified file 'lib/lp/bugs/browser/tests/test_buglisting.py'
--- lib/lp/bugs/browser/tests/test_buglisting.py 2012-02-07 10:43:49 +0000
+++ lib/lp/bugs/browser/tests/test_buglisting.py 2012-04-17 08:56:23 +0000
@@ -150,26 +150,6 @@
find_tag_by_id(browser.contents, 'portlet-tags'),
"portlet-tags should not be shown.")
- def test_searchUnbatched_can_preload_objects(self):
- # BugTaskSearchListingView.searchUnbatched() can optionally
- # preload objects while retrieving the bugtasks.
- product = self.factory.makeProduct()
- bugtask_1 = self.factory.makeBug(product=product).default_bugtask
- bugtask_2 = self.factory.makeBug(product=product).default_bugtask
- view = create_initialized_view(product, '+bugs')
- Store.of(product).invalidate()
- with StormStatementRecorder() as recorder:
- prejoins = [
- (Person, LeftJoin(Person, BugTask.owner == Person.id)),
- ]
- bugtasks = list(view.searchUnbatched(prejoins=prejoins))
- self.assertEqual(
- [bugtask_1, bugtask_2], bugtasks)
- # If the table prejoin failed, then this will issue two
- # additional SQL queries
- [bugtask.owner for bugtask in bugtasks]
- self.assertThat(recorder, HasQueryCount(Equals(2)))
-
def test_search_components_error(self):
# Searching for using components for bug targets that are not a distro
# or distroseries will report an error, but not OOPS. See bug
=== modified file 'lib/lp/bugs/interfaces/bugtarget.py'
--- lib/lp/bugs/interfaces/bugtarget.py 2012-02-08 06:00:46 +0000
+++ lib/lp/bugs/interfaces/bugtarget.py 2012-04-17 08:56:23 +0000
@@ -252,7 +252,7 @@
hardware_owner_is_subscribed_to_bug=False,
hardware_is_linked_to_bug=False, linked_branches=None,
linked_blueprints=None, structural_subscriber=None,
- modified_since=None, created_since=None, prejoins=[]):
+ modified_since=None, created_since=None):
"""Search the IBugTasks reported on this entity.
:search_params: a BugTaskSearchParams object
=== modified file 'lib/lp/bugs/interfaces/bugtask.py'
--- lib/lp/bugs/interfaces/bugtask.py 2012-03-22 19:36:38 +0000
+++ lib/lp/bugs/interfaces/bugtask.py 2012-04-17 08:56:23 +0000
@@ -1531,9 +1531,6 @@
:param search_params: a BugTaskSearchParams object
:param args: any number of BugTaskSearchParams objects
- :param prejoins: (keyword) A sequence of tuples
- (table, table_join) which should be pre-joined in addition
- to the default prejoins.
If more than one BugTaskSearchParams is given, return the union of
IBugTasks which match any of them, with the results ordered by the
=== modified file 'lib/lp/bugs/interfaces/malone.py'
--- lib/lp/bugs/interfaces/malone.py 2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/interfaces/malone.py 2012-04-17 08:56:23 +0000
@@ -33,7 +33,7 @@
"""Application root for malone."""
export_as_webservice_collection(IBug)
- def searchTasks(search_params, prejoins=[]):
+ def searchTasks(search_params):
"""Search IBugTasks with the given search parameters."""
bug_count = Attribute("The number of bugs recorded in Launchpad")
=== modified file 'lib/lp/bugs/model/bugtarget.py'
--- lib/lp/bugs/model/bugtarget.py 2012-02-08 06:00:46 +0000
+++ lib/lp/bugs/model/bugtarget.py 2012-04-17 08:56:23 +0000
@@ -81,7 +81,7 @@
hardware_owner_is_subscribed_to_bug=False,
hardware_is_linked_to_bug=False, linked_branches=None,
linked_blueprints=None, modified_since=None,
- created_since=None, prejoins=[]):
+ created_since=None):
"""See `IHasBugs`."""
if status is None:
# If no statuses are supplied, default to the
@@ -97,10 +97,9 @@
del kwargs['self']
del kwargs['user']
del kwargs['search_params']
- del kwargs['prejoins']
search_params = BugTaskSearchParams.fromSearchForm(user, **kwargs)
self._customizeSearchParams(search_params)
- return BugTaskSet().search(search_params, prejoins=prejoins)
+ return BugTaskSet().search(search_params)
def _customizeSearchParams(self, search_params):
"""Customize `search_params` for a specific target."""
=== modified file 'lib/lp/bugs/model/bugtask.py'
--- lib/lp/bugs/model/bugtask.py 2012-04-12 10:12:59 +0000
+++ lib/lp/bugs/model/bugtask.py 2012-04-17 08:56:23 +0000
@@ -112,6 +112,7 @@
from lp.registry.model.pillar import pillar_sort_key
from lp.registry.model.sourcepackagename import SourcePackageName
from lp.services import features
+from lp.services.database.bulk import load_related
from lp.services.database.constants import UTC_NOW
from lp.services.database.datetimecol import UtcDateTimeCol
from lp.services.database.enumcol import EnumCol
@@ -1504,9 +1505,6 @@
:param _noprejoins: Private internal parameter to BugTaskSet which
disables all use of prejoins : consolidated from code paths that
claim they were inefficient and unwanted.
- :param prejoins: A sequence of tuples (table, table_join) which
- which should be pre-joined in addition to the default prejoins.
- This parameter has no effect if _noprejoins is True.
"""
# Prevent circular import problems.
from lp.registry.model.product import Product
@@ -1514,41 +1512,18 @@
from lp.bugs.model.bugtasksearch import search_bugs
_noprejoins = kwargs.get('_noprejoins', False)
if _noprejoins:
- prejoins = []
- resultrow = BugTask
eager_load = None
else:
- requested_joins = kwargs.get('prejoins', [])
- # NB: We could save later work by predicting what sort of
- # targets we might be interested in here, but as at any
- # point we're dealing with relatively few results, this is
- # likely to be a small win.
- prejoins = [
- (Bug, Join(Bug, BugTask.bug == Bug.id))] + requested_joins
-
- def eager_load(results):
- product_ids = set([row[0].productID for row in results])
- product_ids.discard(None)
- pkgname_ids = set(
- [row[0].sourcepackagenameID for row in results])
- pkgname_ids.discard(None)
- store = IStore(BugTask)
- if product_ids:
- list(store.find(Product, Product.id.is_in(product_ids)))
- if pkgname_ids:
- list(store.find(SourcePackageName,
- SourcePackageName.id.is_in(pkgname_ids)))
- resultrow = (BugTask, Bug)
- additional_result_objects = [
- table for table, join in requested_joins
- if table not in resultrow]
- resultrow = resultrow + tuple(additional_result_objects)
- return search_bugs(resultrow, prejoins, eager_load, (params,) + args)
+ def eager_load(rows):
+ load_related(Bug, rows, ['bugID'])
+ load_related(Product, rows, ['productID'])
+ load_related(SourcePackageName, rows, ['sourcepackagenameID'])
+ return search_bugs(BugTask, eager_load, (params,) + args)
def searchBugIds(self, params):
"""See `IBugTaskSet`."""
from lp.bugs.model.bugtasksearch import search_bugs
- return search_bugs(BugTask.bugID, [], None, [params]).result_set
+ return search_bugs(BugTask.bugID, None, [params]).result_set
def countBugs(self, user, contexts, group_on):
"""See `IBugTaskSet`."""
=== modified file 'lib/lp/bugs/model/bugtasksearch.py'
--- lib/lp/bugs/model/bugtasksearch.py 2012-04-13 05:32:26 +0000
+++ lib/lp/bugs/model/bugtasksearch.py 2012-04-17 08:56:23 +0000
@@ -201,12 +201,10 @@
return comp == None
-def search_bugs(resultrow, prejoins, pre_iter_hook, alternatives):
+def search_bugs(resultrow, pre_iter_hook, alternatives):
"""Return a Storm result set for the given search parameters.
:param resultrow: The type of data returned by the query.
- :param prejoins: A sequence of Storm SQL row instances which are
- pre-joined.
:param pre_iter_hook: An optional pre-iteration hook used for eager
loading bug targets for list views.
:param alternatives: A sequence of BugTaskSearchParams instances, the
@@ -225,14 +223,13 @@
decorators.append(bugtask_decorator)
if has_duplicate_results:
- origin = _build_origin(join_tables, [], clauseTables)
- outer_origin = _build_origin(orderby_joins, prejoins, [])
+ origin = _build_origin(join_tables, clauseTables)
+ outer_origin = _build_origin(orderby_joins, [])
subquery = Select(BugTask.id, where=query, tables=origin)
result = store.using(*outer_origin).find(
resultrow, In(BugTask.id, subquery))
else:
- origin = _build_origin(
- join_tables + orderby_joins, prejoins, clauseTables)
+ origin = _build_origin(join_tables + orderby_joins, clauseTables)
result = store.using(*origin).find(resultrow, query)
else:
results = []
@@ -240,7 +237,7 @@
for params in alternatives:
[query, clauseTables, decorator, join_tables,
has_duplicate_results, with_clause] = _build_query(params)
- origin = _build_origin(join_tables, [], clauseTables)
+ origin = _build_origin(join_tables, clauseTables)
localstore = store
if with_clause:
localstore = store.with_(with_clause)
@@ -253,13 +250,10 @@
resultset = reduce(lambda l, r: l.union(r), results)
origin = _build_origin(
- orderby_joins, prejoins, [],
+ orderby_joins, [],
start_with=Alias(resultset._get_select(), "BugTask"))
result = store.using(*origin).find(resultrow)
- if prejoins:
- decorators.insert(0, itemgetter(0))
-
result.order_by(orderby_expression)
return DecoratedResultSet(
result,
@@ -267,25 +261,20 @@
pre_iter_hook=pre_iter_hook)
-def _build_origin(join_tables, prejoin_tables, clauseTables,
- start_with=BugTask):
+def _build_origin(join_tables, clauseTables, start_with=BugTask):
"""Build the parameter list for Store.using().
:param join_tables: A sequence of tables that should be joined
as returned by _build_query(). Each element has the form
(table, join), where table is the table to join and join
is a Storm Join or LeftJoin instance.
- :param prejoin_tables: A sequence of tables that should additionally
- be joined. Each element has the form (table, join),
- where table is the table to join and join is a Storm Join
- or LeftJoin instance.
:param clauseTables: A sequence of tables that should appear in
the FROM clause of a query. The join condition is defined in
the WHERE clause.
- Tables may appear simultaneously in join_tables, prejoin_tables
- and in clauseTables. This method ensures that each table
- appears exactly once in the returned sequence.
+ Tables may appear simultaneously in join_tables and in clauseTables.
+ This method ensures that each table appears exactly once in the
+ returned sequence.
"""
origin = [start_with]
already_joined = set(origin)
@@ -294,10 +283,6 @@
origin.append(join)
if table is not None:
already_joined.add(table)
- for table, join in prejoin_tables:
- if table not in already_joined:
- origin.append(join)
- already_joined.add(table)
for table in clauseTables:
if table not in already_joined:
origin.append(table)
=== modified file 'lib/lp/bugs/tests/test_bugtarget.py'
--- lib/lp/bugs/tests/test_bugtarget.py 2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/tests/test_bugtarget.py 2012-04-17 08:56:23 +0000
@@ -16,33 +16,25 @@
import random
import unittest
-from storm.expr import LeftJoin
-from storm.store import Store
-from testtools.matchers import Equals
from zope.component import getUtility
from lp.bugs.interfaces.bug import CreateBugParams
from lp.bugs.interfaces.bugtask import (
- BugTaskSearchParams,
BugTaskStatus,
IBugTaskSet,
)
-from lp.bugs.model.bugtask import BugTask
from lp.registry.interfaces.distribution import (
IDistribution,
IDistributionSet,
)
from lp.registry.interfaces.product import IProductSet
from lp.registry.interfaces.projectgroup import IProjectGroupSet
-from lp.registry.model.milestone import Milestone
from lp.services.webapp.interfaces import ILaunchBag
from lp.testing import (
person_logged_in,
- StormStatementRecorder,
TestCaseWithFactory,
)
from lp.testing.layers import DatabaseFunctionalLayer
-from lp.testing.matchers import HasQueryCount
from lp.testing.systemdocs import (
LayeredDocFileSuite,
setUp,
@@ -208,101 +200,6 @@
self.assertTrue(bug.canBeAQuestion())
-class TestBugTargetSearchTasks(TestCaseWithFactory):
- """Tests of IHasBugs.searchTasks()."""
-
- layer = DatabaseFunctionalLayer
-
- def setUp(self):
- super(TestBugTargetSearchTasks, self).setUp()
- self.bug = self.factory.makeBug()
- self.target = self.bug.default_bugtask.target
- self.milestone = self.factory.makeMilestone(product=self.target)
- with person_logged_in(self.target.owner):
- self.bug.default_bugtask.transitionToMilestone(
- self.milestone, self.target.owner)
- self.store = Store.of(self.bug)
- self.store.flush()
- self.store.invalidate()
-
- def test_preload_other_objects(self):
- # We can prejoin objects in calls of searchTasks().
-
- # Without prejoining the table Milestone, accessing the
- # BugTask property milestone requires an extra query.
- with StormStatementRecorder() as recorder:
- params = BugTaskSearchParams(user=None)
- found_tasks = self.target.searchTasks(params)
- found_tasks[0].milestone
- self.assertThat(recorder, HasQueryCount(Equals(2)))
-
- # When we prejoin Milestone, the milestone of our bugtask is
- # already loaded during the main search query.
- self.store.invalidate()
- with StormStatementRecorder() as recorder:
- params = BugTaskSearchParams(user=None)
- prejoins = [(Milestone,
- LeftJoin(Milestone,
- BugTask.milestone == Milestone.id))]
- found_tasks = self.target.searchTasks(params, prejoins=prejoins)
- found_tasks[0].milestone
- self.assertThat(recorder, HasQueryCount(Equals(1)))
-
- def test_preload_other_objects_for_person_search_no_params_passed(self):
- # We can prejoin objects in calls of Person.searchTasks().
- owner = self.bug.owner
- with StormStatementRecorder() as recorder:
- found_tasks = owner.searchTasks(None, user=None)
- found_tasks[0].milestone
- self.assertThat(recorder, HasQueryCount(Equals(2)))
-
- self.store.invalidate()
- with StormStatementRecorder() as recorder:
- prejoins = [(Milestone,
- LeftJoin(Milestone,
- BugTask.milestone == Milestone.id))]
- found_tasks = owner.searchTasks(
- None, user=None, prejoins=prejoins)
- found_tasks[0].milestone
- self.assertThat(recorder, HasQueryCount(Equals(1)))
-
- def test_preload_other_objects_for_person_search_no_keywords_passed(self):
- # We can prejoin objects in calls of Person.searchTasks().
- owner = self.bug.owner
- params = BugTaskSearchParams(user=None, owner=owner)
- with StormStatementRecorder() as recorder:
- found_tasks = owner.searchTasks(params)
- found_tasks[0].milestone
- self.assertThat(recorder, HasQueryCount(Equals(2)))
-
- self.store.invalidate()
- with StormStatementRecorder() as recorder:
- prejoins = [(Milestone,
- LeftJoin(Milestone,
- BugTask.milestone == Milestone.id))]
- found_tasks = owner.searchTasks(params, prejoins=prejoins)
- found_tasks[0].milestone
- self.assertThat(recorder, HasQueryCount(Equals(1)))
-
- def test_preload_other_objects_for_person_search_keywords_passed(self):
- # We can prejoin objects in calls of Person.searchTasks().
- owner = self.bug.owner
- params = BugTaskSearchParams(user=None, owner=owner)
- with StormStatementRecorder() as recorder:
- found_tasks = owner.searchTasks(params, order_by=BugTask.id)
- found_tasks[0].milestone
- self.assertThat(recorder, HasQueryCount(Equals(2)))
-
- self.store.invalidate()
- with StormStatementRecorder() as recorder:
- prejoins = [(Milestone,
- LeftJoin(Milestone,
- BugTask.milestone == Milestone.id))]
- found_tasks = owner.searchTasks(params, prejoins=prejoins)
- found_tasks[0].milestone
- self.assertThat(recorder, HasQueryCount(Equals(1)))
-
-
def test_suite():
"""Return the `IBugTarget` TestSuite."""
suite = unittest.TestSuite()
=== modified file 'lib/lp/bugs/tests/test_bugtask_search.py'
--- lib/lp/bugs/tests/test_bugtask_search.py 2012-04-12 22:50:15 +0000
+++ lib/lp/bugs/tests/test_bugtask_search.py 2012-04-17 08:56:23 +0000
@@ -10,9 +10,6 @@
import unittest
import pytz
-from storm.expr import Join
-from storm.store import Store
-from testtools.matchers import Equals
from zope.component import getUtility
from zope.security.proxy import removeSecurityProxy
@@ -26,7 +23,6 @@
IBugTaskSet,
)
from lp.bugs.model.bugsummary import BugSummary
-from lp.bugs.model.bugtask import BugTask
from lp.registry.interfaces.distribution import IDistribution
from lp.registry.interfaces.distributionsourcepackage import (
IDistributionSourcePackage,
@@ -35,7 +31,6 @@
from lp.registry.interfaces.person import IPersonSet
from lp.registry.interfaces.product import IProduct
from lp.registry.interfaces.sourcepackage import ISourcePackage
-from lp.registry.model.person import Person
from lp.services.searchbuilder import (
all,
any,
@@ -43,14 +38,12 @@
)
from lp.testing import (
person_logged_in,
- StormStatementRecorder,
TestCaseWithFactory,
)
from lp.testing.layers import (
DatabaseFunctionalLayer,
LaunchpadFunctionalLayer,
)
-from lp.testing.matchers import HasQueryCount
class SearchTestBase:
@@ -1505,43 +1498,13 @@
class PreloadBugtaskTargets(MultipleParams):
"""Preload bug targets during a BugTaskSet.search() query."""
- def runSearch(self, params, *args, **kw):
+ def runSearch(self, params, *args):
"""Run BugTaskSet.search() and preload bugtask target objects."""
- return list(self.bugtask_set.search(
- params, *args, _noprejoins=False, **kw))
+ return list(self.bugtask_set.search(params, *args, _noprejoins=False))
def resultValuesForBugtasks(self, expected_bugtasks):
return expected_bugtasks
- def test_preload_additional_objects(self):
- # It is possible to join additional tables in the search query
- # in order to load related Storm objects during the query.
- store = Store.of(self.bugtasks[0])
- store.invalidate()
-
- # If we do not prejoin the owner, two queries a run
- # in order to retrieve the owner of the bugtask.
- with StormStatementRecorder() as recorder:
- params = self.getBugTaskSearchParams(user=None)
- found_tasks = self.runSearch(params)
- found_tasks[0].owner
- self.assertTrue(len(recorder.statements) > 1)
-
- # If we join the table person on bugtask.owner == person.id
- # the owner object is loaded in the query that retrieves the
- # bugtasks.
- store.invalidate()
- with StormStatementRecorder() as recorder:
- params = self.getBugTaskSearchParams(user=None)
- found_tasks = self.runSearch(
- params,
- prejoins=[(Person, Join(Person, BugTask.owner == Person.id))])
- # More than one query may have been performed
- search_count = recorder.count
- # Accessing the owner does not trigger more queries.
- found_tasks[0].owner
- self.assertThat(recorder, HasQueryCount(Equals(search_count)))
-
class NoPreloadBugtaskTargets(MultipleParams):
"""Do not preload bug targets during a BugTaskSet.search() query."""
=== modified file 'lib/lp/registry/browser/tests/test_person.py'
--- lib/lp/registry/browser/tests/test_person.py 2012-02-28 04:24:19 +0000
+++ lib/lp/registry/browser/tests/test_person.py 2012-04-17 08:56:23 +0000
@@ -1135,16 +1135,6 @@
self.assertEqual(
self.expected_for_search_unbatched, list(view.searchUnbatched()))
- def test_searchUnbatched_with_prejoins(self):
- view = create_initialized_view(self.person, self.view_name)
- Store.of(self.subscribed_bug).invalidate()
- with StormStatementRecorder() as recorder:
- prejoins = [
- (Person, LeftJoin(Person, BugTask.owner == Person.id))]
- bugtasks = view.searchUnbatched(prejoins=prejoins)
- [bugtask.owner for bugtask in bugtasks]
- self.assertThat(recorder, HasQueryCount(LessThan(3)))
-
def test_getMilestoneWidgetValues(self):
view = create_initialized_view(self.person, self.view_name)
milestones = [
=== modified file 'lib/lp/systemhomes.py'
--- lib/lp/systemhomes.py 2012-03-23 06:10:28 +0000
+++ lib/lp/systemhomes.py 2012-04-17 08:56:23 +0000
@@ -119,10 +119,9 @@
def __init__(self):
self.title = 'Malone: the Launchpad bug tracker'
- def searchTasks(self, search_params, prejoins=[]):
+ def searchTasks(self, search_params):
"""See `IMaloneApplication`."""
- return getUtility(IBugTaskSet).search(
- search_params, prejoins=prejoins)
+ return getUtility(IBugTaskSet).search(search_params)
def createBug(self, owner, title, description, target,
security_related=False, private=False, tags=None):