← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:stormify-bug into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:stormify-bug into launchpad:master.

Commit message:
Convert Bug to Storm

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/447358
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:stormify-bug into launchpad:master.
diff --git a/lib/lp/answers/doc/karma.rst b/lib/lp/answers/doc/karma.rst
index 5bc61ef..488a2a3 100644
--- a/lib/lp/answers/doc/karma.rst
+++ b/lib/lp/answers/doc/karma.rst
@@ -216,7 +216,7 @@ Linking to a bug
 ................
 
     >>> from lp.bugs.model.bug import Bug
-    >>> questionbug = firefox_question.linkBug(Bug.get(5))
+    >>> questionbug = firefox_question.linkBug(IStore(Bug).get(Bug, 5))
     Karma added: action=questionlinkedtobug, product=firefox, person=name12
 
 
diff --git a/lib/lp/bugs/browser/bug.py b/lib/lp/bugs/browser/bug.py
index 3a34c23..190ba78 100644
--- a/lib/lp/bugs/browser/bug.py
+++ b/lib/lp/bugs/browser/bug.py
@@ -1202,11 +1202,8 @@ class BugTextView(LaunchpadView):
         else:
             text.append("duplicate-of: ")
 
-        if bug.duplicates:
-            dupes = " ".join(str(dupe.id) for dupe in bug.duplicates)
-            text.append("duplicates: %s" % dupes)
-        else:
-            text.append("duplicates: ")
+        dupes = " ".join(str(dupe.id) for dupe in bug.duplicates)
+        text.append("duplicates: %s" % dupes)
 
         if bug.private:
             # XXX kiko 2007-10-31: this could include date_made_private and
diff --git a/lib/lp/bugs/browser/buglisting.py b/lib/lp/bugs/browser/buglisting.py
index cef7d6e..3b579c7 100644
--- a/lib/lp/bugs/browser/buglisting.py
+++ b/lib/lp/bugs/browser/buglisting.py
@@ -682,7 +682,7 @@ class BugTaskListingItem:
         assignee = None
         if self.assignee_id is not None:
             assignee = self.people[self.assignee_id].displayname
-        reporter = self.people[self.bug.ownerID]
+        reporter = self.people[self.bug.owner_id]
 
         # the case that there is no target context (e.g. viewing bug that
         # are related to a user account) is intercepted
diff --git a/lib/lp/bugs/browser/bugtask.py b/lib/lp/bugs/browser/bugtask.py
index ad3a7a2..adedd6b 100644
--- a/lib/lp/bugs/browser/bugtask.py
+++ b/lib/lp/bugs/browser/bugtask.py
@@ -435,7 +435,7 @@ class BugTaskView(LaunchpadView, BugViewMixin, FeedsMixin):
             self.context = context
         list(
             getUtility(IPersonSet).getPrecachedPersonsFromIDs(
-                [self.context.bug.ownerID], need_validity=True
+                [self.context.bug.owner_id], need_validity=True
             )
         )
 
diff --git a/lib/lp/bugs/doc/bug.rst b/lib/lp/bugs/doc/bug.rst
index e1c54e5..7893e52 100644
--- a/lib/lp/bugs/doc/bug.rst
+++ b/lib/lp/bugs/doc/bug.rst
@@ -263,7 +263,7 @@ private:
     >>> from lp.bugs.model.bug import Bug
     >>> from lp.services.database.interfaces import IStore
 
-    >>> all_bugs = set(IStore(Bug).find(Bug).values(Bug.id))
+    >>> all_bugs = set(IStore(Bug).find(Bug.id))
 
     >>> taskset = getUtility(IBugTaskSet)
     >>> def hidden_bugs():
diff --git a/lib/lp/bugs/doc/bugnotificationrecipients.rst b/lib/lp/bugs/doc/bugnotificationrecipients.rst
index c633ea9..c3688c9 100644
--- a/lib/lp/bugs/doc/bugnotificationrecipients.rst
+++ b/lib/lp/bugs/doc/bugnotificationrecipients.rst
@@ -14,7 +14,8 @@ action:
     >>> from lp.bugs.model.bug import Bug
     >>> from lp.registry.model.distribution import Distribution
     >>> from lp.registry.model.product import Product
-    >>> bug_one = Bug.get(1)
+    >>> from lp.services.database.interfaces import IStore
+    >>> bug_one = IStore(Bug).get(Bug, 1)
     >>> recipients = bug_one.getBugNotificationRecipients()
 
 The instance of BugNotificationRecipients we get back correctly
@@ -124,7 +125,7 @@ additional step is involved. A BugNotificationRecipients instance is
 created, annotating that it represents a master bug (of which we are a
 duplicate of).
 
-    >>> bug_two = Bug.get(2)
+    >>> bug_two = IStore(Bug).get(Bug, 2)
     >>> recipients = BugNotificationRecipients(duplicateof=bug_two)
 
     >>> foo_bar = personset.getByEmail("foo.bar@xxxxxxxxxxxxx")
diff --git a/lib/lp/bugs/doc/bugnotifications.rst b/lib/lp/bugs/doc/bugnotifications.rst
index c7aaeb5..4b4d755 100644
--- a/lib/lp/bugs/doc/bugnotifications.rst
+++ b/lib/lp/bugs/doc/bugnotifications.rst
@@ -354,7 +354,7 @@ this document:
     ...     status=CveStatus.ENTRY,
     ... )
     >>> from lp.bugs.model.bug import Bug
-    >>> bug = Bug.get(1)
+    >>> bug = IStore(Bug).get(Bug, 1)
     >>> bugcve = cve.linkBug(bug)  # note this creates the event and notifies
 
     >>> latest_notification = (
diff --git a/lib/lp/bugs/doc/cve.rst b/lib/lp/bugs/doc/cve.rst
index e06fe5f..86b2a3f 100644
--- a/lib/lp/bugs/doc/cve.rst
+++ b/lib/lp/bugs/doc/cve.rst
@@ -75,7 +75,8 @@ You can link a CVE to a bug. You can also see which CVEs are currently
 linked to a bug:
 
     >>> from lp.bugs.model.bug import Bug
-    >>> b = Bug.get(1)
+    >>> from lp.services.database.interfaces import IStore
+    >>> b = IStore(Bug).get(Bug, 1)
     >>> for c in b.cves:
     ...     print(c.displayname)
     ...
diff --git a/lib/lp/bugs/interfaces/bug.py b/lib/lp/bugs/interfaces/bug.py
index e02f2ff..acf5c6e 100644
--- a/lib/lp/bugs/interfaces/bug.py
+++ b/lib/lp/bugs/interfaces/bug.py
@@ -240,7 +240,7 @@ class IBugView(Interface):
             max_length=50000,
         )
     )
-    ownerID = Int(title=_("Owner"), required=True, readonly=True)
+    owner_id = Int(title=_("Owner"), required=True, readonly=True)
     owner = exported(
         Reference(IPerson, title=_("The owner's IPerson"), readonly=True)
     )
diff --git a/lib/lp/bugs/model/bug.py b/lib/lp/bugs/model/bug.py
index dc2d66b..2db7afe 100644
--- a/lib/lp/bugs/model/bug.py
+++ b/lib/lp/bugs/model/bug.py
@@ -33,6 +33,7 @@ from lazr.lifecycle.snapshot import Snapshot
 from lazr.restful.declarations import error_status
 from storm.expr import (
     SQL,
+    Add,
     And,
     Coalesce,
     Desc,
@@ -170,19 +171,10 @@ from lp.registry.model.pillar import pillar_sort_key
 from lp.registry.model.teammembership import TeamParticipation
 from lp.services.config import config
 from lp.services.database import bulk
-from lp.services.database.constants import UTC_NOW
-from lp.services.database.datetimecol import UtcDateTimeCol
+from lp.services.database.constants import DEFAULT, UTC_NOW
 from lp.services.database.decoratedresultset import DecoratedResultSet
 from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import IStore
-from lp.services.database.sqlbase import SQLBase, sqlvalues
-from lp.services.database.sqlobject import (
-    ForeignKey,
-    IntCol,
-    SQLMultipleJoin,
-    SQLObjectNotFound,
-    StringCol,
-)
 from lp.services.database.stormbase import StormBase
 from lp.services.database.stormexpr import WithMaterialized
 from lp.services.fields import DuplicateBug
@@ -261,7 +253,6 @@ class BugTag(StormBase):
     __storm_table__ = "BugTag"
     id = Int(primary=True)
 
-    bug = ForeignKey(dbName="bug", foreignKey="Bug", notNull=True)
     bug_id = Int(name="bug", allow_none=False)
     bug = Reference(bug_id, "Bug.id")
 
@@ -356,33 +347,36 @@ def update_bug_heat(bug_ids):
 
 
 @implementer(IBug, IInformationType)
-class Bug(SQLBase, InformationTypeMixin):
+class Bug(StormBase, InformationTypeMixin):
     """A bug."""
 
-    _defaultOrder = "-id"
+    __storm_table__ = "Bug"
+    __storm_order__ = "-id"
 
     # db field names
-    name = StringCol(unique=True, default=None)
-    title = StringCol(notNull=True)
-    description = StringCol(notNull=False, default=None)
-    owner = ForeignKey(
-        dbName="owner",
-        foreignKey="Person",
-        storm_validator=validate_public_person,
-        notNull=True,
+    id = Int(primary=True)
+    name = Unicode(default=None)
+    title = Unicode(allow_none=False)
+    description = Unicode(allow_none=True, default=None)
+    owner_id = Int(
+        name="owner", validator=validate_public_person, allow_none=False
+    )
+    owner = Reference(owner_id, "Person.id")
+    duplicateof_id = Int(name="duplicateof", default=None)
+    duplicateof = Reference(duplicateof_id, "Bug.id")
+    datecreated = DateTime(
+        allow_none=False, default=UTC_NOW, tzinfo=timezone.utc
+    )
+    date_last_updated = DateTime(
+        allow_none=False, default=UTC_NOW, tzinfo=timezone.utc
     )
-    duplicateof = ForeignKey(
-        dbName="duplicateof", foreignKey="Bug", default=None
+    date_made_private = DateTime(
+        allow_none=True, default=None, tzinfo=timezone.utc
     )
-    datecreated = UtcDateTimeCol(notNull=True, default=UTC_NOW)
-    date_last_updated = UtcDateTimeCol(notNull=True, default=UTC_NOW)
-    date_made_private = UtcDateTimeCol(notNull=False, default=None)
-    who_made_private = ForeignKey(
-        dbName="who_made_private",
-        foreignKey="Person",
-        storm_validator=validate_public_person,
-        default=None,
+    who_made_private_id = Int(
+        name="who_made_private", validator=validate_public_person, default=None
     )
+    who_made_private = Reference(who_made_private_id, "Person.id")
     information_type = DBEnum(
         enum=InformationType, allow_none=False, default=InformationType.PUBLIC
     )
@@ -397,25 +391,44 @@ class Bug(SQLBase, InformationTypeMixin):
         BugWatch.bug_id,
         order_by=(BugWatch.bugtracker_id, BugWatch.remotebug),
     )
-    duplicates = SQLMultipleJoin("Bug", joinColumn="duplicateof", orderBy="id")
+    duplicates = ReferenceSet("id", "Bug.duplicateof_id", order_by="Bug.id")
     linked_bugbranches = ReferenceSet(
         "id", BugBranch.bug_id, order_by=BugBranch.id
     )
-    date_last_message = UtcDateTimeCol(default=None)
-    number_of_duplicates = IntCol(notNull=True, default=0)
-    message_count = IntCol(notNull=True, default=0)
-    users_affected_count = IntCol(notNull=True, default=0)
-    users_unaffected_count = IntCol(notNull=True, default=0)
-    heat = IntCol(notNull=True, default=0)
-    heat_last_updated = UtcDateTimeCol(default=None)
-    latest_patch_uploaded = UtcDateTimeCol(default=None)
+    date_last_message = DateTime(default=None, tzinfo=timezone.utc)
+    number_of_duplicates = Int(allow_none=False, default=0)
+    message_count = Int(allow_none=False, default=0)
+    users_affected_count = Int(allow_none=False, default=0)
+    users_unaffected_count = Int(allow_none=False, default=0)
+    heat = Int(allow_none=False, default=0)
+    heat_last_updated = DateTime(default=None, tzinfo=timezone.utc)
+    latest_patch_uploaded = DateTime(default=None, tzinfo=timezone.utc)
     lock_status = DBEnum(
         name="lock_status",
         enum=BugLockStatus,
         allow_none=False,
         default=BugLockStatus.UNLOCKED,
     )
-    lock_reason = StringCol(notNull=False, default=None)
+    lock_reason = Unicode(allow_none=True, default=None)
+
+    def __init__(
+        self,
+        title,
+        owner,
+        description=None,
+        datecreated=DEFAULT,
+        date_made_private=None,
+        who_made_private=None,
+        information_type=InformationType.PUBLIC,
+    ):
+        super().__init__()
+        self.title = title
+        self.owner = owner
+        self.description = description
+        self.datecreated = datecreated
+        self.date_made_private = date_made_private
+        self.who_made_private = who_made_private
+        self.information_type = information_type
 
     @property
     def locked(self):
@@ -1905,7 +1918,7 @@ class Bug(SQLBase, InformationTypeMixin):
     def _question_from_bug(self):
         for question in self.questions:
             if (
-                question.owner_id == self.ownerID
+                question.owner_id == self.owner_id
                 and question.datecreated == self.datecreated
             ):
                 return question
@@ -1934,10 +1947,12 @@ class Bug(SQLBase, InformationTypeMixin):
                         # range.
                         slices.append(
                             BugMessage.index
-                            >= SQL(
-                                "(select max(index) from "
-                                "bugmessage where bug=%s) + 1 - %s"
-                                % (sqlvalues(self.id, -slice.start))
+                            >= Add(
+                                Select(
+                                    Max(BugMessage.index),
+                                    where=(BugMessage.bug == self),
+                                ),
+                                slice.start + 1,
                             )
                         )
                     else:
@@ -2397,7 +2412,7 @@ class Bug(SQLBase, InformationTypeMixin):
         try:
             if duplicate_of is not None:
                 field._validate(duplicate_of)
-            if self.duplicates:
+            if not self.duplicates.is_empty():
                 user = getUtility(ILaunchBag).user
                 for duplicate in self.duplicates:
                     old_value = duplicate.duplicateof
@@ -3204,17 +3219,17 @@ class BugSet:
 
     def get(self, bugid):
         """See `IBugSet`."""
-        try:
-            return Bug.get(bugid)
-        except SQLObjectNotFound:
+        bug = IStore(Bug).get(Bug, int(bugid))
+        if bug is None:
             raise NotFoundError(
                 "Unable to locate bug with ID %s." % str(bugid)
             )
+        return bug
 
     def getByNameOrID(self, bugid):
         """See `IBugSet`."""
         if self.valid_bug_name_re.match(bugid):
-            bug = Bug.selectOneBy(name=bugid)
+            bug = IStore(Bug).find(Bug, name=bugid).one()
             if bug is None:
                 raise NotFoundError("Unable to locate bug with ID %s." % bugid)
         else:
@@ -3334,6 +3349,8 @@ class BugSet:
         if params.tags:
             bug.tags = params.tags
 
+        Store.of(bug).flush()
+
         # Link the bug to the message.
         BugMessage(bug=bug, message=params.msg, index=0)
 
@@ -3497,7 +3514,7 @@ def generate_subscription_with(bug, person):
                     BugSubscription,
                     Join(Bug, Bug.id == BugSubscription.bug_id),
                 ],
-                where=Or(Bug.id == bug.id, Bug.duplicateofID == bug.id),
+                where=Or(Bug.id == bug.id, Bug.duplicateof_id == bug.id),
             ),
         ),
         WithMaterialized(
diff --git a/lib/lp/bugs/model/bugtask.py b/lib/lp/bugs/model/bugtask.py
index 2a0dce7..2606bed 100644
--- a/lib/lp/bugs/model/bugtask.py
+++ b/lib/lp/bugs/model/bugtask.py
@@ -1019,7 +1019,7 @@ class BugTask(StormBase):
             return True
         elif (
             self.status == BugTaskStatus.FIXRELEASED
-            and user.id != self.bug.ownerID
+            and user.id != self.bug.owner_id
             and not user.inTeam(self.bug.owner)
         ):
             # The bug reporter can reopen a Fix Released bug.
@@ -1606,7 +1606,7 @@ class BugTaskSet:
 
         people_ids = set(
             [bugtask.assignee_id for bugtask in bugtasks]
-            + [bugtask.bug.ownerID for bugtask in bugtasks]
+            + [bugtask.bug.owner_id for bugtask in bugtasks]
         )
         people = getUtility(IPersonSet).getPrecachedPersonsFromIDs(people_ids)
         return {person.id: person for person in people}
diff --git a/lib/lp/bugs/model/bugtasksearch.py b/lib/lp/bugs/model/bugtasksearch.py
index 9ec4c25..7f7dd20 100644
--- a/lib/lp/bugs/model/bugtasksearch.py
+++ b/lib/lp/bugs/model/bugtasksearch.py
@@ -1105,7 +1105,7 @@ def _build_exclude_conjoined_clause(milestone):
     """
     # XXX: EdwinGrubbs 2010-12-15 bug=682989
     # (ConjoinedPrimary.bug == X) produces the wrong sql, but
-    # (ConjoinedPrimary.bugID == X) works right. This bug applies to
+    # (ConjoinedPrimary.bug_id == X) works right. This bug applies to
     # all foreign keys on the ClassAlias.
 
     # Perform a LEFT JOIN to the conjoined primary bugtask.  If the
diff --git a/lib/lp/bugs/model/personsubscriptioninfo.py b/lib/lp/bugs/model/personsubscriptioninfo.py
index 8e28966..aaff8d4 100644
--- a/lib/lp/bugs/model/personsubscriptioninfo.py
+++ b/lib/lp/bugs/model/personsubscriptioninfo.py
@@ -184,7 +184,7 @@ class PersonSubscriptions:
         # Preload bug owners, then all pillars.
         list(
             getUtility(IPersonSet).getPrecachedPersonsFromIDs(
-                [bug.ownerID for bug in bugs]
+                [bug.owner_id for bug in bugs]
             )
         )
         all_tasks = load_referencing(BugTask, bugs, ["bug_id"])
diff --git a/lib/lp/bugs/stories/bugs/xx-bug-text-pages.rst b/lib/lp/bugs/stories/bugs/xx-bug-text-pages.rst
index bfa0b6e..116baaa 100644
--- a/lib/lp/bugs/stories/bugs/xx-bug-text-pages.rst
+++ b/lib/lp/bugs/stories/bugs/xx-bug-text-pages.rst
@@ -9,14 +9,15 @@ To demonstrate this feature, we'll use bug 1.
 We'll start by adding some attachments to the bug:
 
     >>> from io import BytesIO
-    >>> from lp.services.database.sqlbase import flush_database_updates
-    >>> from lp.testing import login, logout
     >>> from lp.bugs.model.bug import Bug
     >>> from lp.registry.model.person import Person
+    >>> from lp.services.database.interfaces import IStore
+    >>> from lp.services.database.sqlbase import flush_database_updates
+    >>> from lp.testing import login, logout
     >>> login("foo.bar@xxxxxxxxxxxxx")
     >>> mark = Person.selectOneBy(name="mark")
     >>> mark.display_name = "M\xe1rk Sh\xfattlew\xf2rth"
-    >>> bug = Bug.get(1)
+    >>> bug = IStore(Bug).get(Bug, 1)
     >>> content = BytesIO(b"<html><body>bogus</body></html>")
     >>> a1 = bug.addAttachment(
     ...     mark,
diff --git a/lib/lp/bugs/templates/bug-portlet-duplicates.pt b/lib/lp/bugs/templates/bug-portlet-duplicates.pt
index 0a11c96..a2f0afa 100644
--- a/lib/lp/bugs/templates/bug-portlet-duplicates.pt
+++ b/lib/lp/bugs/templates/bug-portlet-duplicates.pt
@@ -3,7 +3,7 @@
     xmlns:metal="http://xml.zope.org/namespaces/metal";
     xmlns:i18n="http://xml.zope.org/namespaces/i18n";
     class="portlet" id="portlet-duplicates"
-    tal:condition="context/duplicates">
+    tal:condition="not: context/duplicates/is_empty">
   <h2>Duplicates of this bug</h2>
   <ul>
     <li tal:repeat="dupe view/duplicates">
diff --git a/lib/lp/bugs/tests/bugs-emailinterface.rst b/lib/lp/bugs/tests/bugs-emailinterface.rst
index 1a8a900..6555137 100644
--- a/lib/lp/bugs/tests/bugs-emailinterface.rst
+++ b/lib/lp/bugs/tests/bugs-emailinterface.rst
@@ -2085,7 +2085,7 @@ An empty unsigned mail to new@malone:
 If we submit an email with no affects command, it is rejected.
 
     >>> from lp.bugs.model.bug import Bug
-    >>> before_count = Bug.select().count()
+    >>> before_count = IStore(Bug).find(Bug).count()
     >>> submit_mail = b"""From: Foo Bar <foo.bar@xxxxxxxxxxxxx>
     ... To: new@xxxxxxxxxxxxxxxxxxxxxxxxx
     ... Date: Fri Jun 17 10:20:23 BST 2005
@@ -2099,7 +2099,7 @@ If we submit an email with no affects command, it is rejected.
     ... """
 
     >>> process_email(submit_mail)
-    >>> before_count == Bug.select().count()
+    >>> before_count == IStore(Bug).find(Bug).count()
     True
 
     >>> print_latest_email()
@@ -2118,7 +2118,7 @@ required. If it is missing, the message is also rejected.
 XXX: Gavin Panella 2009-07-24 bug=404010: The need for this test
 arises from the implementation of MaloneHandler.
 
-    >>> before_count = Bug.select().count()
+    >>> before_count = IStore(Bug).find(Bug).count()
     >>> submit_mail = b"""From: Foo Bar <foo.bar@xxxxxxxxxxxxx>
     ... To: new@xxxxxxxxxxxxxxxxxxxxxxxxx
     ... Date: Fri Jun 17 10:20:23 BST 2005
@@ -2130,7 +2130,7 @@ arises from the implementation of MaloneHandler.
     ... """
 
     >>> process_email(submit_mail)
-    >>> before_count == Bug.select().count()
+    >>> before_count == IStore(Bug).find(Bug).count()
     True
 
     >>> print_latest_email()
@@ -2151,7 +2151,7 @@ edit@bugs).
 XXX: Gavin Panella 2009-07-24 bug=404010: The need for this test
 arises from the implementation of MaloneHandler.
 
-    >>> before_count = Bug.select().count()
+    >>> before_count = IStore(Bug).find(Bug).count()
     >>> submit_mail = b"""\
     ... From: Foo Bar <foo.bar@xxxxxxxxxxxxx>
     ... To: new@xxxxxxxxxxxxxxxxxxxxxxxxx
@@ -2162,7 +2162,7 @@ arises from the implementation of MaloneHandler.
     ... """
 
     >>> process_email(submit_mail)
-    >>> before_count == Bug.select().count()
+    >>> before_count == IStore(Bug).find(Bug).count()
     True
 
     >>> print_latest_email()
@@ -2184,7 +2184,7 @@ bug-related commands do blow up before the check for a bugtask is
 reached. For example, unsubscribing oneself from a private bug then
 linking a CVE.
 
-    >>> before_count = Bug.select().count()
+    >>> before_count = IStore(Bug).find(Bug).count()
     >>> submit_mail = b"""\
     ... From: Foo Bar <foo.bar@xxxxxxxxxxxxx>
     ... To: new@xxxxxxxxxxxxxxxxxxxxxxxxx
@@ -2197,7 +2197,7 @@ linking a CVE.
     ... """
 
     >>> process_email(submit_mail)
-    >>> before_count == Bug.select().count()
+    >>> before_count == IStore(Bug).find(Bug).count()
     True
 
     >>> print_latest_email()
diff --git a/lib/lp/bugs/vocabularies.py b/lib/lp/bugs/vocabularies.py
index 9b337e0..5586ef3 100644
--- a/lib/lp/bugs/vocabularies.py
+++ b/lib/lp/bugs/vocabularies.py
@@ -56,7 +56,6 @@ from lp.services.webapp.vocabulary import (
     CountableIterator,
     IHugeVocabulary,
     NamedSQLObjectVocabulary,
-    SQLObjectVocabularyBase,
     StormVocabularyBase,
 )
 
@@ -85,9 +84,9 @@ class UsesBugsDistributionVocabulary(DistributionVocabulary):
         )
 
 
-class BugVocabulary(SQLObjectVocabularyBase):
+class BugVocabulary(StormVocabularyBase):
     _table = Bug
-    _orderBy = "id"
+    _order_by = "id"
 
 
 @implementer(IHugeVocabulary)
diff --git a/lib/lp/registry/tests/test_person.py b/lib/lp/registry/tests/test_person.py
index e0f005c..3646ff7 100644
--- a/lib/lp/registry/tests/test_person.py
+++ b/lib/lp/registry/tests/test_person.py
@@ -1016,7 +1016,7 @@ class TestPersonStates(TestCaseWithFactory):
         )
 
     def test_Bug_person_validator(self):
-        bug = Bug.select(limit=1)[0]
+        bug = IStore(Bug).find(Bug).first()
         for attr_name in ["owner", "who_made_private"]:
             self.assertRaises(
                 PrivatePersonLinkageError, setattr, bug, attr_name, self.myteam
diff --git a/lib/lp/scripts/harness.py b/lib/lp/scripts/harness.py
index 7be9884..a5a03ec 100644
--- a/lib/lp/scripts/harness.py
+++ b/lib/lp/scripts/harness.py
@@ -77,8 +77,8 @@ def _get_locals():
         ds = DistroSeries.get(1)
         prod = Product.get(1)
         proj = ProjectGroup.get(1)
-        b2 = Bug.get(2)
-        b1 = Bug.get(1)
+        b2 = store.get(Bug, 2)
+        b1 = store.get(Bug, 1)
         s = store.get(Specification, 1)
         q = store.get(Question, 1)
         # Silence unused name warnings
diff --git a/lib/lp/services/database/tests/test_bulk.py b/lib/lp/services/database/tests/test_bulk.py
index 6cdf569..b9f64c8 100644
--- a/lib/lp/services/database/tests/test_bulk.py
+++ b/lib/lp/services/database/tests/test_bulk.py
@@ -252,7 +252,7 @@ class TestLoaders(TestCaseWithFactory):
         expected = {bug.owner for bug in owning_objects}
         self.assertEqual(
             expected,
-            set(bulk.load_related(Person, owning_objects, ["ownerID"])),
+            set(bulk.load_related(Person, owning_objects, ["owner_id"])),
         )
 
     def test_load_referencing(self):
diff --git a/lib/lp/services/statistics/model/statistics.py b/lib/lp/services/statistics/model/statistics.py
index 4b4ff60..f0a182e 100644
--- a/lib/lp/services/statistics/model/statistics.py
+++ b/lib/lp/services/statistics/model/statistics.py
@@ -106,10 +106,10 @@ class LaunchpadStatisticSet:
         getUtility(IPersonSet).updateStatistics()
 
     def _updateMaloneStatistics(self, ztm):
-        self.update("bug_count", Bug.select().count())
+        store = IStore(Bug)
+        self.update("bug_count", store.find(Bug).count())
         ztm.commit()
 
-        store = IStore(BugTask)
         self.update("bugtask_count", store.find(BugTask).count())
         ztm.commit()