launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #28605
[Merge] ~cjwatson/launchpad:stormify-revision into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:stormify-revision into launchpad:master.
Commit message:
Convert Revision and friends to Storm
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/424941
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:stormify-revision into launchpad:master.
diff --git a/lib/lp/code/browser/branchlisting.py b/lib/lp/code/browser/branchlisting.py
index eee45b8..e4c0c47 100644
--- a/lib/lp/code/browser/branchlisting.py
+++ b/lib/lp/code/browser/branchlisting.py
@@ -383,7 +383,7 @@ class BranchListingItemsMixin:
# Cache display information for authors of branches' respective
# last revisions.
getUtility(IPersonSet).getPrecachedPersonsFromIDs(
- [revision.revision_author.personID for revision in revisions],
+ [revision.revision_author.person_id for revision in revisions],
need_icon=True)
# Return a dict keyed on branch id.
diff --git a/lib/lp/code/doc/revision.txt b/lib/lp/code/doc/revision.txt
index 9244c72..3e091bd 100644
--- a/lib/lp/code/doc/revision.txt
+++ b/lib/lp/code/doc/revision.txt
@@ -16,11 +16,15 @@ Interfaces
>>> from lp.code.model.revision import (
... Revision, RevisionAuthor, RevisionParent, RevisionSet)
>>> from lp.code.model.branchrevision import BranchRevision
- >>> verifyObject(IRevision, Revision.get(1))
+ >>> verifyObject(IRevision, IStore(Revision).find(Revision).any())
True
- >>> verifyObject(IRevisionAuthor, RevisionAuthor.get(1))
+ >>> verifyObject(
+ ... IRevisionAuthor,
+ ... IStore(RevisionAuthor).find(RevisionAuthor).any())
True
- >>> verifyObject(IRevisionParent, RevisionParent.get(1))
+ >>> verifyObject(
+ ... IRevisionParent,
+ ... IStore(RevisionParent).find(RevisionParent).any())
True
>>> verifyObject(IRevisionSet, RevisionSet())
True
@@ -59,7 +63,6 @@ while the date_created is the time when the database record was created.
>>> from datetime import datetime
>>> from pytz import UTC
>>> date = datetime(2005, 3, 8, 12, 0, tzinfo=UTC)
- >>> from lp.code.model.revision import Revision
>>> revision_1 = Revision(log_body=log_body_1,
... revision_author=author, revision_id=revision_id_1,
... revision_date=date)
diff --git a/lib/lp/code/interfaces/revision.py b/lib/lp/code/interfaces/revision.py
index 116e2f8..74d8548 100644
--- a/lib/lp/code/interfaces/revision.py
+++ b/lib/lp/code/interfaces/revision.py
@@ -86,7 +86,7 @@ class IRevisionAuthor(Interface):
email = Attribute("The email address extracted from the author text.")
person = PublicPersonChoice(title=_('Author'), required=False,
readonly=False, vocabulary='ValidPersonOrTeam')
- personID = Attribute("The primary key of the person")
+ person_id = Attribute("The primary key of the person")
def linkToLaunchpadPerson():
"""Attempt to link the revision author to a Launchpad `Person`.
diff --git a/lib/lp/code/model/branch.py b/lib/lp/code/model/branch.py
index 2b940ba..d538579 100644
--- a/lib/lp/code/model/branch.py
+++ b/lib/lp/code/model/branch.py
@@ -1177,7 +1177,8 @@ class Branch(SQLBase, WebhookTargetMixin, BzrIdentityMixin):
tip_revision_id = self.last_scanned_id
if tip_revision_id is None:
return None
- return Revision.selectOneBy(revision_id=tip_revision_id)
+ return IStore(Revision).find(
+ Revision, revision_id=tip_revision_id).one()
def updateScannedDetails(self, db_revision, revision_count):
"""See `IBranch`."""
diff --git a/lib/lp/code/model/revision.py b/lib/lp/code/model/revision.py
index 2f04cd3..ad4ad74 100644
--- a/lib/lp/code/model/revision.py
+++ b/lib/lp/code/model/revision.py
@@ -14,6 +14,7 @@ from datetime import (
timedelta,
)
import email
+from operator import itemgetter
from breezy.revision import NULL_REVISION
import pytz
@@ -28,10 +29,13 @@ from storm.expr import (
)
from storm.locals import (
Bool,
+ DateTime,
Int,
Min,
Reference,
+ ReferenceSet,
Storm,
+ Unicode,
)
from storm.store import Store
from zope.component import getUtility
@@ -55,22 +59,12 @@ from lp.services.database.constants import (
DEFAULT,
UTC_NOW,
)
-from lp.services.database.datetimecol import UtcDateTimeCol
+from lp.services.database.decoratedresultset import DecoratedResultSet
from lp.services.database.interfaces import (
IMasterStore,
IStore,
)
-from lp.services.database.sqlbase import (
- quote,
- SQLBase,
- )
-from lp.services.database.sqlobject import (
- BoolCol,
- ForeignKey,
- IntCol,
- SQLMultipleJoin,
- StringCol,
- )
+from lp.services.database.stormbase import StormBase
from lp.services.helpers import shortlist
from lp.services.identity.interfaces.emailaddress import (
EmailAddressStatus,
@@ -79,28 +73,44 @@ from lp.services.identity.interfaces.emailaddress import (
@implementer(IRevision)
-class Revision(SQLBase):
+class Revision(StormBase):
"""See IRevision."""
- date_created = UtcDateTimeCol(notNull=True, default=DEFAULT)
- log_body = StringCol(notNull=True)
+ __storm_table__ = "Revision"
- revision_author_id = Int(name='revision_author', allow_none=False)
- revision_author = Reference(revision_author_id, 'RevisionAuthor.id')
+ id = Int(primary=True)
+
+ date_created = DateTime(
+ name="date_created", allow_none=False, default=DEFAULT,
+ tzinfo=pytz.UTC)
+ log_body = Unicode(name="log_body", allow_none=False)
+
+ revision_author_id = Int(name="revision_author", allow_none=False)
+ revision_author = Reference(revision_author_id, "RevisionAuthor.id")
- revision_id = StringCol(notNull=True, alternateID=True,
- alternateMethodName='byRevisionID')
- revision_date = UtcDateTimeCol(notNull=False)
+ revision_id = Unicode(name="revision_id", allow_none=False)
+ revision_date = DateTime(
+ name="revision_date", allow_none=True, tzinfo=pytz.UTC)
- karma_allocated = BoolCol(default=False, notNull=True)
+ karma_allocated = Bool(
+ name="karma_allocated", default=False, allow_none=False)
- properties = SQLMultipleJoin('RevisionProperty', joinColumn='revision')
+ properties = ReferenceSet("id", "RevisionProperty.revision_id")
+
+ def __init__(self, log_body, revision_author, revision_id,
+ revision_date=None, date_created=DEFAULT):
+ super().__init__()
+ self.log_body = log_body
+ self.revision_author = revision_author
+ self.revision_id = revision_id
+ self.revision_date = revision_date
+ self.date_created = date_created
@property
def parents(self):
"""See IRevision.parents"""
- return shortlist(RevisionParent.selectBy(
- revision=self, orderBy='sequence'))
+ return shortlist(IStore(RevisionParent).find(
+ RevisionParent, revision=self).order_by(RevisionParent.sequence))
@property
def parent_ids(self):
@@ -172,18 +182,32 @@ class Revision(SQLBase):
result_set.order_by(Asc(BranchRevision.sequence))
else:
result_set.order_by(
- Branch.ownerID != self.revision_author.personID,
+ Branch.ownerID != self.revision_author.person_id,
Asc(BranchRevision.sequence))
return result_set.first()
@implementer(IRevisionAuthor)
-class RevisionAuthor(SQLBase):
+class RevisionAuthor(StormBase):
+
+ __storm_table__ = "RevisionAuthor"
+
+ id = Int(primary=True)
+
+ name = Unicode(name="name", allow_none=False)
+
+ email = Unicode(name="email", allow_none=True, default=None)
- _table = 'RevisionAuthor'
+ person_id = Int(
+ name="person", allow_none=True, validator=validate_public_person,
+ default=None)
+ person = Reference(person_id, "Person.id")
- name = StringCol(notNull=True, alternateID=True)
+ def __init__(self, name, email=None):
+ super().__init__()
+ self.name = name
+ self.email = email
@property
def name_without_email(self):
@@ -196,10 +220,6 @@ class RevisionAuthor(SQLBase):
return self.name
return email.utils.parseaddr(self.name)[0]
- email = StringCol(notNull=False, default=None)
- person = ForeignKey(dbName='person', foreignKey='Person', notNull=False,
- storm_validator=validate_public_person, default=None)
-
def linkToLaunchpadPerson(self):
"""See `IRevisionAuthor`."""
if self.person is not None or self.email is None:
@@ -210,42 +230,59 @@ class RevisionAuthor(SQLBase):
return False
# Only accept an email address that is validated.
if lp_email.status != EmailAddressStatus.NEW:
- self.personID = lp_email.personID
+ self.person_id = lp_email.personID
return True
else:
return False
@implementer(IRevisionParent)
-class RevisionParent(SQLBase):
+class RevisionParent(StormBase):
"""The association between a revision and its parent."""
- _table = 'RevisionParent'
+ __storm_table__ = "RevisionParent"
+
+ id = Int(primary=True)
+
+ revision_id = Int(name="revision", allow_none=False)
+ revision = Reference(revision_id, "Revision.id")
- revision = ForeignKey(
- dbName='revision', foreignKey='Revision', notNull=True)
+ sequence = Int(allow_none=False)
+ parent_id = Unicode(allow_none=False)
- sequence = IntCol(notNull=True)
- parent_id = StringCol(notNull=True)
+ def __init__(self, revision, sequence, parent_id):
+ super().__init__()
+ self.revision = revision
+ self.sequence = sequence
+ self.parent_id = parent_id
@implementer(IRevisionProperty)
-class RevisionProperty(SQLBase):
+class RevisionProperty(StormBase):
"""A property on a revision. See IRevisionProperty."""
- _table = 'RevisionProperty'
+ __storm_table__ = "RevisionProperty"
+
+ id = Int(primary=True)
+
+ revision_id = Int(name="revision", allow_none=False)
+ revision = Reference(revision_id, "Revision.id")
+
+ name = Unicode(allow_none=False)
+ value = Unicode(allow_none=False)
- revision = ForeignKey(
- dbName='revision', foreignKey='Revision', notNull=True)
- name = StringCol(notNull=True)
- value = StringCol(notNull=True)
+ def __init__(self, revision, name, value):
+ super().__init__()
+ self.revision = revision
+ self.name = name
+ self.value = value
@implementer(IRevisionSet)
class RevisionSet:
def getByRevisionId(self, revision_id):
- return Revision.selectOneBy(revision_id=revision_id)
+ return IStore(Revision).find(Revision, revision_id=revision_id).one()
def _createRevisionAuthor(self, revision_author):
"""Extract out the email and check to see if it matches a Person."""
@@ -254,8 +291,11 @@ class RevisionSet:
if '@' not in email_address:
email_address = None
+ store = IMasterStore(RevisionAuthor)
author = RevisionAuthor(name=revision_author, email=email_address)
+ store.add(author)
author.linkToLaunchpadPerson()
+ store.flush()
return author
def new(self, revision_id, log_body, revision_date, revision_author,
@@ -395,12 +435,12 @@ class RevisionSet:
parent_data.append((db_id, sequence, parent_id))
# Create all RevisionParent objects.
create((
- RevisionParent.revisionID, RevisionParent.sequence,
+ RevisionParent.revision_id, RevisionParent.sequence,
RevisionParent.parent_id), parent_data)
# Create all RevisionProperty objects.
create((
- RevisionProperty.revisionID, RevisionProperty.name,
+ RevisionProperty.revision_id, RevisionProperty.name,
RevisionProperty.value), property_data)
@staticmethod
@@ -413,15 +453,20 @@ class RevisionSet:
def getTipRevisionsForBranches(self, branches):
"""See `IRevisionSet`."""
+ # Circular import.
+ from lp.code.model.branch import Branch
+
# If there are no branch_ids, then return None.
branch_ids = [branch.id for branch in branches]
if not branch_ids:
return None
- return Revision.select("""
- Branch.id in %s AND
- Revision.revision_id = Branch.last_scanned_id
- """ % quote(branch_ids),
- clauseTables=['Branch'], prejoins=['revision_author'])
+ return DecoratedResultSet(
+ IStore(Revision).find(
+ (Revision, RevisionAuthor),
+ Branch.id.is_in(branch_ids),
+ Revision.revision_id == Branch.last_scanned_id,
+ Revision.revision_author_id == RevisionAuthor.id),
+ result_decorator=itemgetter(0))
@staticmethod
def getRecentRevisionsForProduct(product, days):
@@ -475,7 +520,7 @@ class RevisionSet:
if person.is_team:
origin.append(
Join(TeamParticipation,
- RevisionAuthor.personID == TeamParticipation.personID))
+ RevisionAuthor.person_id == TeamParticipation.personID))
person_condition = TeamParticipation.team == person
else:
person_condition = RevisionAuthor.person == person
@@ -623,7 +668,7 @@ class RevisionCache(Storm):
revision_author_id = Int(name='revision_author', allow_none=False)
revision_author = Reference(revision_author_id, 'RevisionAuthor.id')
- revision_date = UtcDateTimeCol(notNull=True)
+ revision_date = DateTime(allow_none=False, tzinfo=pytz.UTC)
product_id = Int(name='product', allow_none=True)
product = Reference(product_id, 'Product.id')
diff --git a/lib/lp/code/model/revisioncache.py b/lib/lp/code/model/revisioncache.py
index d43096c..593805b 100644
--- a/lib/lp/code/model/revisioncache.py
+++ b/lib/lp/code/model/revisioncache.py
@@ -74,7 +74,7 @@ class GenericRevisionCollection:
# is different.
author = Func(
'coalesce',
- RevisionAuthor.personID,
+ RevisionAuthor.person_id,
SQL(0) - RevisionAuthor.id)
expressions = [
RevisionCache.revision_author == RevisionAuthor.id]
@@ -140,7 +140,7 @@ class GenericRevisionCollection:
if person.is_team:
query = [
TeamParticipation.team == person,
- RevisionAuthor.personID == TeamParticipation.personID]
+ RevisionAuthor.person_id == TeamParticipation.personID]
else:
query = [RevisionAuthor.person == person]
diff --git a/lib/lp/code/model/tests/test_revision.py b/lib/lp/code/model/tests/test_revision.py
index bdd0f7a..2061884 100644
--- a/lib/lp/code/model/tests/test_revision.py
+++ b/lib/lp/code/model/tests/test_revision.py
@@ -248,9 +248,9 @@ class TestRevisionSet(TestCaseWithFactory):
self.assertEqual({'prop1': 'foo'}, rev_1.getProperties())
rev_2 = self.revision_set.getByRevisionId('rev-2')
self.assertEqual(['rev-1'], rev_2.parent_ids)
- # Really, less than 9 is great, but if the count improves, we should
+ # Really, less than 8 is great, but if the count improves, we should
# tighten this restriction.
- self.assertThat(recorder, HasQueryCount(Equals(8)))
+ self.assertThat(recorder, HasQueryCount(Equals(7)))
def test_acquireRevisionAuthors(self):
# AcquireRevisionAuthors creates new authors only if none exists with
diff --git a/lib/lp/code/model/tests/test_revisionauthor.py b/lib/lp/code/model/tests/test_revisionauthor.py
index 9941c7f..0e033f5 100644
--- a/lib/lp/code/model/tests/test_revisionauthor.py
+++ b/lib/lp/code/model/tests/test_revisionauthor.py
@@ -12,6 +12,7 @@ from lp.code.model.revision import (
)
from lp.registry.interfaces.person import IPersonSet
from lp.scripts.garbo import RevisionAuthorEmailLinker
+from lp.services.database.interfaces import IStore
from lp.services.identity.interfaces.emailaddress import EmailAddressStatus
from lp.services.log.logger import DevNullLogger
from lp.testing import TestCase
@@ -139,7 +140,8 @@ class TestNewlyValidatedEmailsLinkRevisionAuthors(MakeHarryTestCase):
self.author = RevisionSet()._createRevisionAuthor(
'"Harry Potter" <harry@xxxxxxxxxxxxx>')
# Reget the revision author as we have crossed a transaction boundary.
- self.author = RevisionAuthor.byName(self.author.name)
+ self.author = IStore(RevisionAuthor).find(
+ RevisionAuthor, name=self.author.name).one()
def test_validated_email_updates(self):
# A newly validated email for a user.
diff --git a/lib/lp/codehosting/scanner/tests/test_bzrsync.py b/lib/lp/codehosting/scanner/tests/test_bzrsync.py
index 6d6fba5..216b400 100644
--- a/lib/lp/codehosting/scanner/tests/test_bzrsync.py
+++ b/lib/lp/codehosting/scanner/tests/test_bzrsync.py
@@ -364,7 +364,8 @@ class TestBzrSync(BzrSyncTestCase):
author = "Another Author <another@xxxxxxxxxxx>"
self.commitRevision(committer=author)
self.syncAndCount(new_revisions=1, new_numbers=1, new_authors=1)
- db_author = RevisionAuthor.selectOneBy(name=author)
+ db_author = IStore(RevisionAuthor).find(
+ RevisionAuthor, name=author).one()
self.assertEqual(db_author.name, author)
def test_new_parent(self):
@@ -399,8 +400,8 @@ class TestBzrSync(BzrSyncTestCase):
timestamp=1000000000.0, timezone=28800)
self.syncAndCount(
new_revisions=2, new_numbers=2, new_parents=1, new_authors=2)
- rev_1 = Revision.selectOneBy(revision_id='rev-1')
- rev_2 = Revision.selectOneBy(revision_id='rev-2')
+ rev_1 = IStore(Revision).find(Revision, revision_id="rev-1").one()
+ rev_2 = IStore(Revision).find(Revision, revision_id="rev-2").one()
UTC = pytz.timezone('UTC')
dt = datetime.datetime.fromtimestamp(1000000000.0, UTC)
self.assertEqual(rev_1.revision_date, dt)
diff --git a/lib/lp/scripts/garbo.py b/lib/lp/scripts/garbo.py
index ff17b49..90736eb 100644
--- a/lib/lp/scripts/garbo.py
+++ b/lib/lp/scripts/garbo.py
@@ -910,7 +910,7 @@ class RevisionAuthorEmailLinker(TunableLoop):
result = self.author_store.find(
RevisionAuthor,
RevisionAuthor.id >= self.next_author_id,
- RevisionAuthor.personID == None,
+ RevisionAuthor.person_id == None,
RevisionAuthor.email != None)
result.order_by(RevisionAuthor.id)
authors = list(result[:chunk_size])
@@ -931,10 +931,10 @@ class RevisionAuthorEmailLinker(TunableLoop):
if emails:
for author in authors:
- personID = emails.get(author.email.lower())
- if personID is None:
+ person_id = emails.get(author.email.lower())
+ if person_id is None:
continue
- author.personID = personID
+ author.person_id = person_id
self.next_author_id = authors[-1].id + 1
transaction.commit()