Merge ~cjwatson/launchpad:stormify-branchsubscription into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 36a2613199b8aa47be605967fcde06a869af2c53
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:stormify-branchsubscription
Merge into: launchpad:master
Diff against target: 263 lines (+62/-45)
8 files modified
lib/lp/code/browser/branchsubscription.py (+2/-2)
lib/lp/code/browser/decorations.py (+2/-2)
lib/lp/code/interfaces/branchsubscription.py (+2/-2)
lib/lp/code/model/branch.py (+11/-11)
lib/lp/code/model/branchsubscription.py (+37/-20)
lib/lp/registry/model/sharingjob.py (+4/-4)
lib/lp/services/database/bulk.py (+2/-2)
lib/lp/services/database/tests/test_bulk.py (+2/-2)
Reviewer Review Type Date Requested Status
Thiago F. Pappacena (community) Approve
Review via email: mp+381293@code.launchpad.net

Commit message

Convert BranchSubscription to Storm

To post a comment you must log in.
Revision history for this message
Thiago F. Pappacena (pappacena) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/code/browser/branchsubscription.py b/lib/lp/code/browser/branchsubscription.py
2index ca3833f..fbd98bc 100644
3--- a/lib/lp/code/browser/branchsubscription.py
4+++ b/lib/lp/code/browser/branchsubscription.py
5@@ -1,4 +1,4 @@
6-# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
7+# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
8 # GNU Affero General Public License version 3 (see the file LICENSE).
9
10 __metaclass__ = type
11@@ -43,7 +43,7 @@ class BranchPortletSubscribersContent(LaunchpadView):
12 # The security adaptor will do the job also but we don't want or need
13 # the expense of running several complex SQL queries.
14 subscriptions = list(self.context.subscriptions)
15- person_ids = [sub.personID for sub in subscriptions]
16+ person_ids = [sub.person_id for sub in subscriptions]
17 list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(
18 person_ids, need_validity=True))
19 if self.user is not None:
20diff --git a/lib/lp/code/browser/decorations.py b/lib/lp/code/browser/decorations.py
21index a7ac2d6..c4b0ae7 100644
22--- a/lib/lp/code/browser/decorations.py
23+++ b/lib/lp/code/browser/decorations.py
24@@ -1,4 +1,4 @@
25-# Copyright 2010 Canonical Ltd. This software is licensed under the
26+# Copyright 2010-2020 Canonical Ltd. This software is licensed under the
27 # GNU Affero General Public License version 3 (see the file LICENSE).
28
29 """Decorated model objects used in the browser code."""
30@@ -95,7 +95,7 @@ class DecoratedBranch(BzrIdentityMixin):
31 """
32 if user is None:
33 return False
34- return user.id in [sub.personID for sub in self.subscriptions]
35+ return user.id in [sub.person_id for sub in self.subscriptions]
36
37 @cachedproperty
38 def latest_revisions(self):
39diff --git a/lib/lp/code/interfaces/branchsubscription.py b/lib/lp/code/interfaces/branchsubscription.py
40index c885c78..e5a8861 100644
41--- a/lib/lp/code/interfaces/branchsubscription.py
42+++ b/lib/lp/code/interfaces/branchsubscription.py
43@@ -1,4 +1,4 @@
44-# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
45+# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
46 # GNU Affero General Public License version 3 (see the file LICENSE).
47
48 """Bazaar branch subscription interfaces."""
49@@ -38,7 +38,7 @@ class IBranchSubscription(Interface):
50 export_as_webservice_entry()
51
52 id = Int(title=_('ID'), readonly=True, required=True)
53- personID = Int(title=_('Person ID'), required=True, readonly=True)
54+ person_id = Int(title=_('Person ID'), required=True, readonly=True)
55 person = exported(
56 PersonChoice(
57 title=_('Person'), required=True, vocabulary='ValidPersonOrTeam',
58diff --git a/lib/lp/code/model/branch.py b/lib/lp/code/model/branch.py
59index 7811d45..b214c86 100644
60--- a/lib/lp/code/model/branch.py
61+++ b/lib/lp/code/model/branch.py
62@@ -24,8 +24,6 @@ from six.moves.urllib_parse import urlsplit
63 from sqlobject import (
64 ForeignKey,
65 IntCol,
66- SQLMultipleJoin,
67- SQLRelatedJoin,
68 StringCol,
69 )
70 from storm.expr import (
71@@ -299,7 +297,8 @@ class Branch(SQLBase, WebhookTargetMixin, BzrIdentityMixin):
72 # this branch.
73 self.information_type = information_type
74 self._reconcileAccess()
75- if information_type in PRIVATE_INFORMATION_TYPES and self.subscribers:
76+ if (information_type in PRIVATE_INFORMATION_TYPES and
77+ not self.subscribers.is_empty()):
78 # Grant the subscriber access if they can't see the branch.
79 service = getUtility(IService, 'sharing')
80 blind_subscribers = service.getPeopleWithoutAccess(
81@@ -438,11 +437,11 @@ class Branch(SQLBase, WebhookTargetMixin, BzrIdentityMixin):
82 result = result.order_by(Desc(BranchRevision.sequence))
83 return DecoratedResultSet(result, operator.itemgetter(0))
84
85- subscriptions = SQLMultipleJoin(
86- 'BranchSubscription', joinColumn='branch', orderBy='id')
87- subscribers = SQLRelatedJoin(
88- 'Person', joinColumn='branch', otherColumn='person',
89- intermediateTable='BranchSubscription', orderBy='name')
90+ subscriptions = ReferenceSet(
91+ 'id', 'BranchSubscription.branch_id', order_by='BranchSubscription.id')
92+ subscribers = ReferenceSet(
93+ 'id', 'BranchSubscription.branch_id',
94+ 'BranchSubscription.person_id', 'Person.id', order_by='Person.name')
95
96 bug_branches = ReferenceSet(
97 'id', 'BugBranch.branch_id', order_by='BugBranch.id')
98@@ -1071,9 +1070,10 @@ class Branch(SQLBase, WebhookTargetMixin, BzrIdentityMixin):
99 """See `IBranch`."""
100 if person is None:
101 return None
102- subscription = BranchSubscription.selectOneBy(
103- person=person, branch=self)
104- return subscription
105+ return Store.of(self).find(
106+ BranchSubscription,
107+ BranchSubscription.person == person,
108+ BranchSubscription.branch == self).one()
109
110 def getSubscriptionsByLevel(self, notification_levels):
111 """See `IBranch`."""
112diff --git a/lib/lp/code/model/branchsubscription.py b/lib/lp/code/model/branchsubscription.py
113index 49df1c9..74ac06f 100644
114--- a/lib/lp/code/model/branchsubscription.py
115+++ b/lib/lp/code/model/branchsubscription.py
116@@ -1,10 +1,15 @@
117-# Copyright 2009 Canonical Ltd. This software is licensed under the
118+# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
119 # GNU Affero General Public License version 3 (see the file LICENSE).
120
121+from __future__ import absolute_import, print_function, unicode_literals
122+
123 __metaclass__ = type
124 __all__ = ['BranchSubscription']
125
126-from sqlobject import ForeignKey
127+from storm.locals import (
128+ Int,
129+ Reference,
130+ )
131 from zope.interface import implementer
132
133 from lp.code.enums import (
134@@ -18,29 +23,41 @@ from lp.code.security import BranchSubscriptionEdit
135 from lp.registry.interfaces.person import validate_person
136 from lp.registry.interfaces.role import IPersonRoles
137 from lp.services.database.constants import DEFAULT
138-from lp.services.database.enumcol import EnumCol
139-from lp.services.database.sqlbase import SQLBase
140+from lp.services.database.enumcol import DBEnum
141+from lp.services.database.stormbase import StormBase
142
143
144 @implementer(IBranchSubscription, IHasBranchTarget)
145-class BranchSubscription(SQLBase):
146+class BranchSubscription(StormBase):
147 """A relationship between a person and a branch."""
148
149- _table = 'BranchSubscription'
150-
151- person = ForeignKey(
152- dbName='person', foreignKey='Person',
153- storm_validator=validate_person, notNull=True)
154- branch = ForeignKey(dbName='branch', foreignKey='Branch', notNull=True)
155- notification_level = EnumCol(enum=BranchSubscriptionNotificationLevel,
156- notNull=True, default=DEFAULT)
157- max_diff_lines = EnumCol(enum=BranchSubscriptionDiffSize,
158- notNull=False, default=DEFAULT)
159- review_level = EnumCol(enum=CodeReviewNotificationLevel,
160- notNull=True, default=DEFAULT)
161- subscribed_by = ForeignKey(
162- dbName='subscribed_by', foreignKey='Person',
163- storm_validator=validate_person, notNull=True)
164+ __storm_table__ = 'BranchSubscription'
165+
166+ id = Int(primary=True)
167+
168+ person_id = Int(name='person', allow_none=False, validator=validate_person)
169+ person = Reference(person_id, 'Person.id')
170+ branch_id = Int(name='branch', allow_none=False)
171+ branch = Reference(branch_id, 'Branch.id')
172+ notification_level = DBEnum(enum=BranchSubscriptionNotificationLevel,
173+ allow_none=False, default=DEFAULT)
174+ max_diff_lines = DBEnum(enum=BranchSubscriptionDiffSize,
175+ allow_none=True, default=DEFAULT)
176+ review_level = DBEnum(enum=CodeReviewNotificationLevel,
177+ allow_none=False, default=DEFAULT)
178+ subscribed_by_id = Int(
179+ name='subscribed_by', allow_none=False, validator=validate_person)
180+ subscribed_by = Reference(subscribed_by_id, 'Person.id')
181+
182+ def __init__(self, person, branch, notification_level, max_diff_lines,
183+ review_level, subscribed_by):
184+ super(BranchSubscription, self).__init__()
185+ self.person = person
186+ self.branch = branch
187+ self.notification_level = notification_level
188+ self.max_diff_lines = max_diff_lines
189+ self.review_level = review_level
190+ self.subscribed_by = subscribed_by
191
192 @property
193 def target(self):
194diff --git a/lib/lp/registry/model/sharingjob.py b/lib/lp/registry/model/sharingjob.py
195index a3dd532..c069213 100644
196--- a/lib/lp/registry/model/sharingjob.py
197+++ b/lib/lp/registry/model/sharingjob.py
198@@ -1,4 +1,4 @@
199-# Copyright 2012-2015 Canonical Ltd. This software is licensed under the
200+# Copyright 2012-2020 Canonical Ltd. This software is licensed under the
201 # GNU Affero General Public License version 3 (see the file LICENSE).
202
203 """Job classes related to the sharing feature are in here."""
204@@ -418,7 +418,7 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived):
205 TeamParticipation.personID,
206 where=TeamParticipation.team == self.grantee)))
207 branch_filters.append(
208- In(BranchSubscription.personID,
209+ In(BranchSubscription.person_id,
210 Select(
211 TeamParticipation.personID,
212 where=TeamParticipation.team == self.grantee)))
213@@ -447,10 +447,10 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived):
214 sub.person, self.requestor, ignore_permissions=True)
215 if branch_filters:
216 branch_filters.append(Not(
217- Or(*get_branch_privacy_filter(BranchSubscription.personID))))
218+ Or(*get_branch_privacy_filter(BranchSubscription.person_id))))
219 branch_subscriptions = IStore(BranchSubscription).using(
220 BranchSubscription,
221- Join(Branch, Branch.id == BranchSubscription.branchID)
222+ Join(Branch, Branch.id == BranchSubscription.branch_id)
223 ).find(BranchSubscription, *branch_filters).config(
224 distinct=True)
225 for sub in branch_subscriptions:
226diff --git a/lib/lp/services/database/bulk.py b/lib/lp/services/database/bulk.py
227index f73bbf8..67dff02 100644
228--- a/lib/lp/services/database/bulk.py
229+++ b/lib/lp/services/database/bulk.py
230@@ -1,4 +1,4 @@
231-# Copyright 2010-2018 Canonical Ltd. This software is licensed under the
232+# Copyright 2010-2020 Canonical Ltd. This software is licensed under the
233 # GNU Affero General Public License version 3 (see the file LICENSE).
234
235 """Optimized bulk operations against the database."""
236@@ -158,7 +158,7 @@ def load_referencing(object_type, owning_objects, reference_keys,
237 At this point, all the objects should be of the same type, but that
238 constraint could be lifted in future.
239 :param reference_keys: A list of attributes that should be used to select
240- object_type keys. e.g. ['branchID']
241+ object_type keys. e.g. ['branch_id']
242 :param extra_conditions: A list of Storm clauses that will be used in the
243 final query.
244 :return: A list of object_type where any of reference_keys refered to the
245diff --git a/lib/lp/services/database/tests/test_bulk.py b/lib/lp/services/database/tests/test_bulk.py
246index 43f903f..d1efe56 100644
247--- a/lib/lp/services/database/tests/test_bulk.py
248+++ b/lib/lp/services/database/tests/test_bulk.py
249@@ -1,4 +1,4 @@
250-# Copyright 2010-2018 Canonical Ltd. This software is licensed under the
251+# Copyright 2010-2020 Canonical Ltd. This software is licensed under the
252 # GNU Affero General Public License version 3 (see the file LICENSE).
253
254 """Test the bulk database functions."""
255@@ -264,7 +264,7 @@ class TestLoaders(TestCaseWithFactory):
256 self.assertNotEqual(0, len(expected))
257 self.assertEqual(expected,
258 set(bulk.load_referencing(BranchSubscription, owned_objects,
259- ['branchID'])))
260+ ['branch_id'])))
261
262
263 class TestCreate(TestCaseWithFactory):

Subscribers

People subscribed via source and target branches

to status/vote changes: