← Back to team overview

launchpad-reviewers team mailing list archive

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

 

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

Commit message:
Convert lp.services.worlddata to Storm

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/391112
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:stormify-worlddata into launchpad:master.
diff --git a/lib/lp/services/worlddata/model/country.py b/lib/lp/services/worlddata/model/country.py
index 387a84a..e46988f 100644
--- a/lib/lp/services/worlddata/model/country.py
+++ b/lib/lp/services/worlddata/model/country.py
@@ -6,18 +6,18 @@ from __future__ import absolute_import, print_function, unicode_literals
 __metaclass__ = type
 __all__ = ['Country', 'CountrySet', 'Continent']
 
-import six
-from sqlobject import (
-    ForeignKey,
-    SQLRelatedJoin,
-    StringCol,
+from storm.locals import (
+    Int,
+    Reference,
+    ReferenceSet,
+    Unicode,
     )
 from zope.interface import implementer
 
 from lp.app.errors import NotFoundError
 from lp.services.database.constants import DEFAULT
 from lp.services.database.interfaces import IStore
-from lp.services.database.sqlbase import SQLBase
+from lp.services.database.stormbase import StormBase
 from lp.services.worlddata.interfaces.country import (
     IContinent,
     ICountry,
@@ -26,27 +26,25 @@ from lp.services.worlddata.interfaces.country import (
 
 
 @implementer(ICountry)
-class Country(SQLBase):
+class Country(StormBase):
     """A country."""
 
-    _table = 'Country'
+    __storm_table__ = 'Country'
 
     # default to listing newest first
-    _defaultOrder = 'name'
+    __storm_order__ = 'name'
 
     # db field names
-    name = StringCol(dbName='name', unique=True, notNull=True)
-    iso3166code2 = StringCol(dbName='iso3166code2', unique=True,
-                             notNull=True)
-    iso3166code3 = StringCol(dbName='iso3166code3', unique=True,
-                             notNull=True)
-    title = StringCol(dbName='title', notNull=False, default=DEFAULT)
-    description = StringCol(dbName='description')
-    continent = ForeignKey(
-        dbName='continent', foreignKey='Continent', default=None)
-    languages = SQLRelatedJoin(
-        six.ensure_str('Language'), joinColumn='country',
-        otherColumn='language', intermediateTable='SpokenIn')
+    id = Int(primary=True)
+    name = Unicode(name='name', allow_none=False)
+    iso3166code2 = Unicode(name='iso3166code2', allow_none=False)
+    iso3166code3 = Unicode(name='iso3166code3', allow_none=False)
+    title = Unicode(name='title', allow_none=True, default=DEFAULT)
+    description = Unicode(name='description')
+    continent_id = Int(name='continent', default=None)
+    continent = Reference(continent_id, 'Continent.id')
+    languages = ReferenceSet(
+        id, 'SpokenIn.country_id', 'SpokenIn.language_id', 'Language.id')
 
 
 @implementer(ICountrySet)
@@ -54,13 +52,14 @@ class CountrySet:
     """A set of countries"""
 
     def __getitem__(self, iso3166code2):
-        country = Country.selectOneBy(iso3166code2=iso3166code2)
+        country = IStore(Country).find(
+            Country, iso3166code2=iso3166code2).one()
         if country is None:
             raise NotFoundError(iso3166code2)
         return country
 
     def __iter__(self):
-        for row in Country.select():
+        for row in IStore(Country).find(Country):
             yield row
 
     def getByName(self, name):
@@ -77,11 +76,12 @@ class CountrySet:
 
 
 @implementer(IContinent)
-class Continent(SQLBase):
+class Continent(StormBase):
     """See IContinent."""
 
-    _table = 'Continent'
-    _defaultOrder = ['name', 'id']
+    __storm_table__ = 'Continent'
+    __storm_order__ = ['name', 'id']
 
-    name = StringCol(unique=True, notNull=True)
-    code = StringCol(unique=True, notNull=True)
+    id = Int(primary=True)
+    name = Unicode(allow_none=False)
+    code = Unicode(allow_none=False)
diff --git a/lib/lp/services/worlddata/model/language.py b/lib/lp/services/worlddata/model/language.py
index 9142207..105230e 100644
--- a/lib/lp/services/worlddata/model/language.py
+++ b/lib/lp/services/worlddata/model/language.py
@@ -11,13 +11,6 @@ __all__ = [
     ]
 
 import six
-from sqlobject import (
-    BoolCol,
-    IntCol,
-    SQLObjectNotFound,
-    SQLRelatedJoin,
-    StringCol,
-    )
 from storm.expr import (
     And,
     Count,
@@ -26,6 +19,12 @@ from storm.expr import (
     LeftJoin,
     Or,
     )
+from storm.locals import (
+    Bool,
+    Int,
+    ReferenceSet,
+    Unicode,
+    )
 from zope.interface import implementer
 
 from lp.app.errors import NotFoundError
@@ -34,12 +33,13 @@ from lp.registry.model.karma import (
     KarmaCategory,
     )
 from lp.services.database.decoratedresultset import DecoratedResultSet
-from lp.services.database.enumcol import EnumCol
+from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import (
     ISlaveStore,
     IStore,
     )
-from lp.services.database.sqlbase import SQLBase
+from lp.services.database.stormbase import StormBase
+from lp.services.database.stormexpr import IsTrue
 from lp.services.helpers import ensure_unicode
 from lp.services.propertycache import (
     cachedproperty,
@@ -53,28 +53,46 @@ from lp.services.worlddata.interfaces.language import (
 
 
 @implementer(ILanguage)
-class Language(SQLBase):
-
-    _table = 'Language'
-
-    code = StringCol(dbName='code', notNull=True, unique=True)
-    uuid = StringCol(dbName='uuid', notNull=False, default=None)
-    nativename = StringCol(dbName='nativename')
-    englishname = StringCol(dbName='englishname')
-    pluralforms = IntCol(dbName='pluralforms')
-    pluralexpression = StringCol(dbName='pluralexpression')
-    visible = BoolCol(dbName='visible', notNull=True)
-    direction = EnumCol(
-        dbName='direction', notNull=True, schema=TextDirection,
+class Language(StormBase):
+
+    __storm_table__ = 'Language'
+
+    id = Int(primary=True)
+    code = Unicode(name='code', allow_none=False)
+    uuid = Unicode(name='uuid', allow_none=True, default=None)
+    nativename = Unicode(name='nativename')
+    englishname = Unicode(name='englishname')
+    pluralforms = Int(name='pluralforms')
+    pluralexpression = Unicode(name='pluralexpression')
+    visible = Bool(name='visible', allow_none=False)
+    direction = DBEnum(
+        name='direction', allow_none=False, enum=TextDirection,
         default=TextDirection.LTR)
 
-    translation_teams = SQLRelatedJoin(
-        six.ensure_str('Person'), joinColumn="language",
-        intermediateTable='Translator', otherColumn='translator')
+    translation_teams = ReferenceSet(
+        id, 'Translator.languageID',
+        'Translator.translatorID', 'Person.<primary key>')
+
+    _countries = ReferenceSet(
+        id, 'SpokenIn.language_id', 'SpokenIn.country_id', 'Country.id')
+
+    def __init__(self, code, nativename=None, englishname=None,
+                 pluralforms=None, pluralexpression=None, visible=True,
+                 direction=TextDirection.LTR):
+        super(Language, self).__init__()
+        self.code = code
+        self.nativename = nativename
+        self.englishname = englishname
+        self.pluralforms = pluralforms
+        self.pluralexpression = pluralexpression
+        self.visible = visible
+        self.direction = direction
 
-    _countries = SQLRelatedJoin(
-        six.ensure_str('Country'), joinColumn='language',
-        otherColumn='country', intermediateTable='SpokenIn')
+    def addCountry(self, country):
+        self._countries.add(country)
+
+    def removeCountry(self, country):
+        self._countries.remove(country)
 
     # Define a read/write property `countries` so it can be passed
     # to language administration `LaunchpadFormView`.
@@ -200,9 +218,8 @@ class LanguageSet:
 
     @property
     def _visible_languages(self):
-        return Language.select(
-            'visible IS TRUE',
-            orderBy='englishname')
+        return IStore(Language).find(
+            Language, IsTrue(Language.visible)).order_by(Language.englishname)
 
     @property
     def common_languages(self):
@@ -220,9 +237,8 @@ class LanguageSet:
         """See `ILanguageSet`."""
         result = IStore(Language).find(
                 Language,
-                Language.visible == True if only_visible else True,
-            ).order_by(
-            Language.englishname)
+                IsTrue(Language.visible) if only_visible else True,
+            ).order_by(Language.englishname)
         if want_translators_count:
             def preload_translators_count(languages):
                 from lp.registry.model.person import PersonLanguage
@@ -245,7 +261,8 @@ class LanguageSet:
 
     def __iter__(self):
         """See `ILanguageSet`."""
-        return iter(Language.select(orderBy='englishname'))
+        return iter(
+            IStore(Language).find(Language).order_by(Language.englishname))
 
     def __getitem__(self, code):
         """See `ILanguageSet`."""
@@ -258,14 +275,11 @@ class LanguageSet:
 
     def get(self, language_id):
         """See `ILanguageSet`."""
-        try:
-            return Language.get(language_id)
-        except SQLObjectNotFound:
-            return None
+        return IStore(Language).get(Language, language_id)
 
     def getLanguageByCode(self, code):
         """See `ILanguageSet`."""
-        assert isinstance(code, six.string_types), (
+        assert isinstance(code, six.text_type), (
             "%s is not a valid type for 'code'" % type(code))
         return IStore(Language).find(Language, code=code).one()
 
@@ -300,10 +314,13 @@ class LanguageSet:
                        pluralforms=None, pluralexpression=None, visible=True,
                        direction=TextDirection.LTR):
         """See `ILanguageSet`."""
-        return Language(
+        store = IStore(Language)
+        language = Language(
             code=code, englishname=englishname, nativename=nativename,
             pluralforms=pluralforms, pluralexpression=pluralexpression,
             visible=visible, direction=direction)
+        store.add(language)
+        return language
 
     def search(self, text):
         """See `ILanguageSet`."""
diff --git a/lib/lp/services/worlddata/model/spokenin.py b/lib/lp/services/worlddata/model/spokenin.py
index 6d2f06c..46d00f5 100644
--- a/lib/lp/services/worlddata/model/spokenin.py
+++ b/lib/lp/services/worlddata/model/spokenin.py
@@ -6,22 +6,27 @@ from __future__ import absolute_import, print_function, unicode_literals
 __metaclass__ = type
 __all__ = ['SpokenIn']
 
-from sqlobject import ForeignKey
+from storm.locals import (
+    Int,
+    Reference,
+    )
 from zope.interface import implementer
 
-from lp.services.database.sqlbase import SQLBase
+from lp.services.database.stormbase import StormBase
 from lp.services.worlddata.interfaces.spokenin import ISpokenIn
 
 
 @implementer(ISpokenIn)
-class SpokenIn(SQLBase):
+class SpokenIn(StormBase):
     """A way of telling which languages are spoken in which countries.
 
     This table maps a language which is SpokenIn a country.
     """
 
-    _table = 'SpokenIn'
+    __storm_table__ = 'SpokenIn'
 
-    country = ForeignKey(dbName='country', notNull=True, foreignKey='Country')
-    language = ForeignKey(dbName='language', notNull=True,
-                          foreignKey='Language')
+    id = Int(primary=True)
+    country_id = Int(name='country', allow_none=False)
+    country = Reference(country_id, 'Country.id')
+    language_id = Int(name='language', allow_none=False)
+    language = Reference(language_id, 'Language.id')
diff --git a/lib/lp/services/worlddata/vocabularies.py b/lib/lp/services/worlddata/vocabularies.py
index 6c96021..5634cbc 100644
--- a/lib/lp/services/worlddata/vocabularies.py
+++ b/lib/lp/services/worlddata/vocabularies.py
@@ -20,7 +20,10 @@ from zope.schema.vocabulary import (
     SimpleVocabulary,
     )
 
-from lp.services.webapp.vocabulary import SQLObjectVocabularyBase
+from lp.services.webapp.vocabulary import (
+    NamedStormVocabulary,
+    StormVocabularyBase,
+    )
 from lp.services.worlddata.interfaces.language import (
     ILanguage,
     ILanguageSet,
@@ -43,24 +46,20 @@ def TimezoneNameVocabulary(context=None):
     return _timezone_vocab
 
 
-# Country.name may have non-ASCII characters, so we can't use
-# NamedSQLObjectVocabulary here.
-
-class CountryNameVocabulary(SQLObjectVocabularyBase):
+class CountryNameVocabulary(NamedStormVocabulary):
     """A vocabulary for country names."""
 
     _table = Country
-    _orderBy = 'name'
 
     def toTerm(self, obj):
         return SimpleTerm(obj, obj.id, obj.name)
 
 
-class LanguageVocabulary(SQLObjectVocabularyBase):
+class LanguageVocabulary(StormVocabularyBase):
     """All the languages known by Launchpad."""
 
     _table = Language
-    _orderBy = 'englishname'
+    _order_by = 'englishname'
 
     def __contains__(self, language):
         """See `IVocabulary`."""
diff --git a/lib/lp/testing/factory.py b/lib/lp/testing/factory.py
index b7dc38f..7759cd4 100644
--- a/lib/lp/testing/factory.py
+++ b/lib/lp/testing/factory.py
@@ -2619,13 +2619,13 @@ class BareLaunchpadObjectFactory(ObjectFactory):
                      plural_expression=None):
         """Makes a language given the language_code and name."""
         if language_code is None:
-            language_code = self.getUniqueString('lang')
+            language_code = self.getUniqueUnicode('lang')
         if name is None:
             name = "Language %s" % language_code
         if plural_expression is None and pluralforms is not None:
             # If the number of plural forms is known, the language
             # should also have a plural expression and vice versa.
-            plural_expression = 'n %% %d' % pluralforms
+            plural_expression = u'n %% %d' % pluralforms
 
         language_set = getUtility(ILanguageSet)
         return language_set.createLanguage(
diff --git a/lib/lp/translations/vocabularies.py b/lib/lp/translations/vocabularies.py
index 0da0c5f..79cef40 100644
--- a/lib/lp/translations/vocabularies.py
+++ b/lib/lp/translations/vocabularies.py
@@ -3,6 +3,8 @@
 
 """Translations vocabularies."""
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 __metaclass__ = type
 
 __all__ = [
@@ -20,6 +22,7 @@ from zope.schema.vocabulary import SimpleTerm
 
 from lp.registry.interfaces.distroseries import IDistroSeries
 from lp.services.database.sqlbase import sqlvalues
+from lp.services.database.stormexpr import IsTrue
 from lp.services.webapp.vocabulary import (
     NamedSQLObjectVocabulary,
     SQLObjectVocabularyBase,
@@ -59,9 +62,8 @@ class TranslatableLanguageVocabulary(LanguageVocabulary):
 
         Iterate languages that are visible and not English.
         """
-        languages = self._table.select(
-            "Language.code != 'en' AND Language.visible = True",
-            orderBy=self._orderBy)
+        languages = self._entries.find(
+            self._table.code != 'en', IsTrue(self._table.visible))
         for language in languages:
             yield self.toTerm(language)