SQL Migrations: Rewrite table creation completely.
authorElrond <elrond+mediagoblin.org@samba-tng.org>
Sat, 24 Nov 2012 18:19:18 +0000 (19:19 +0100)
committerElrond <elrond+mediagoblin.org@samba-tng.org>
Sat, 24 Nov 2012 18:23:08 +0000 (19:23 +0100)
We have migrations creating new tables. Those currently use
"raw" table definitions. This easily gives errors (we
already had this problem).

So instead rewrite those to use declarative tables and use
those to create new tables. Just copy the new table over to
the migration, strip it down to the bare minimum, rename to
_v0, base it on declarative_base() and be done!

Do this for the current migrations.

mediagoblin/db/sql/migrations.py
mediagoblin/plugins/oauth/migrations.py

index 1d822cd97bc05a813264093afc99634a82858021..bc68caa33da05d94b63febdf128b5d0779816894 100644 (file)
 import datetime
 
 from sqlalchemy import (MetaData, Table, Column, Boolean, SmallInteger,
-                        Integer, Unicode, UnicodeText, DateTime, ForeignKey)
+                        Integer, Unicode, UnicodeText, DateTime,
+                        ForeignKey, UniqueConstraint)
+from sqlalchemy.ext.declarative import declarative_base
 
 from mediagoblin.db.sql.util import RegisterMigration
-from mediagoblin.db.sql.models import MediaEntry, Collection, User, \
-        ProcessingMetaData
+from mediagoblin.db.sql.models import MediaEntry, Collection, User
 
 MIGRATIONS = {}
 
@@ -65,29 +66,40 @@ def add_transcoding_progress(db_conn):
     db_conn.commit()
 
 
+class Collection_v0(declarative_base()):
+    __tablename__ = "core__collections"
+
+    id = Column(Integer, primary_key=True)
+    title = Column(Unicode, nullable=False)
+    slug = Column(Unicode)
+    created = Column(DateTime, nullable=False, default=datetime.datetime.now,
+        index=True)
+    description = Column(UnicodeText)
+    creator = Column(Integer, ForeignKey(User.id), nullable=False)
+    items = Column(Integer, default=0)
+
+class CollectionItem_v0(declarative_base()):
+    __tablename__ = "core__collection_items"
+
+    id = Column(Integer, primary_key=True)
+    media_entry = Column(
+        Integer, ForeignKey(MediaEntry.id), nullable=False, index=True)
+    collection = Column(Integer, ForeignKey(Collection.id), nullable=False)
+    note = Column(UnicodeText, nullable=True)
+    added = Column(DateTime, nullable=False, default=datetime.datetime.now)
+    position = Column(Integer)
+
+    ## This should be activated, normally.
+    ## But this would change the way the next migration used to work.
+    ## So it's commented for now.
+    # __table_args__ = (
+    #     UniqueConstraint('collection', 'media_entry'),
+    #     {})
+
 @RegisterMigration(4, MIGRATIONS)
 def add_collection_tables(db_conn):
-    metadata = MetaData(bind=db_conn.bind)
-
-    collection = Table('core__collections', metadata,
-                       Column('id', Integer, primary_key=True),
-                       Column('title', Unicode, nullable=False),
-                       Column('slug', Unicode),
-                       Column('created', DateTime, nullable=False, default=datetime.datetime.now, index=True),
-                       Column('description', UnicodeText),
-                       Column('creator', Integer, ForeignKey(User.id), nullable=False),
-                       Column('items', Integer, default=0))
-
-    collection_item = Table('core__collection_items', metadata,
-                            Column('id', Integer, primary_key=True),
-                            Column('media_entry', Integer, ForeignKey(MediaEntry.id), nullable=False, index=True),
-                            Column('collection', Integer, ForeignKey(Collection.id), nullable=False),
-                            Column('note', UnicodeText, nullable=True),
-                            Column('added', DateTime, nullable=False, default=datetime.datetime.now),
-                            Column('position', Integer))
-
-    collection.create()
-    collection_item.create()
+    Collection_v0.__table__.create(db_conn.bind)
+    CollectionItem_v0.__table__.create(db_conn.bind)
 
     db_conn.commit()
 
@@ -104,15 +116,15 @@ def add_mediaentry_collected(db_conn):
     db_conn.commit()
 
 
-@RegisterMigration(6, MIGRATIONS)
-def create_processing_metadata_table(db):
-    metadata = MetaData(bind=db.bind)
+class ProcessingMetaData_v0(declarative_base()):
+    __tablename__ = 'core__processing_metadata'
 
-    metadata_table = Table('core__processing_metadata', metadata,
-            Column('id', Integer, primary_key=True),
-            Column('media_entry_id', Integer, ForeignKey(MediaEntry.id),
-                nullable=False, index=True),
-            Column('callback_url', Unicode))
+    id = Column(Integer, primary_key=True)
+    media_entry_id = Column(Integer, ForeignKey(MediaEntry.id), nullable=False,
+            index=True)
+    callback_url = Column(Unicode)
 
-    metadata_table.create()
+@RegisterMigration(6, MIGRATIONS)
+def create_processing_metadata_table(db):
+    ProcessingMetaData_v0.__table__.create(db.bind)
     db.commit()
index f2af3907659045b5566b7dd730acd0e631572762..797e7585bd461dd2902f4b69f710b744a7a62c66 100644 (file)
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from sqlalchemy import MetaData, Table
+from datetime import datetime, timedelta
+from sqlalchemy import (MetaData, Table, Column,
+                        Integer, Unicode, Enum, DateTime, ForeignKey)
+from sqlalchemy.ext.declarative import declarative_base
 
 from mediagoblin.db.sql.util import RegisterMigration
+from mediagoblin.db.sql.models import User
 
-from mediagoblin.plugins.oauth.models import OAuthClient, OAuthToken, \
-        OAuthUserClient, OAuthCode
 
 MIGRATIONS = {}
 
 
+class OAuthClient_v0(declarative_base()):
+    __tablename__ = 'oauth__client'
+
+    id = Column(Integer, primary_key=True)
+    created = Column(DateTime, nullable=False,
+            default=datetime.now)
+
+    name = Column(Unicode)
+    description = Column(Unicode)
+
+    identifier = Column(Unicode, unique=True, index=True)
+    secret = Column(Unicode, index=True)
+
+    owner_id = Column(Integer, ForeignKey(User.id))
+    redirect_uri = Column(Unicode)
+
+    type = Column(Enum(
+        u'confidential',
+        u'public',
+        name=u'oauth__client_type'))
+
+
+class OAuthUserClient_v0(declarative_base()):
+    __tablename__ = 'oauth__user_client'
+    id = Column(Integer, primary_key=True)
+
+    user_id = Column(Integer, ForeignKey(User.id))
+    client_id = Column(Integer, ForeignKey(OAuthClient_v0.id))
+
+    state = Column(Enum(
+        u'approved',
+        u'rejected',
+        name=u'oauth__relation_state'))
+
+
+class OAuthToken_v0(declarative_base()):
+    __tablename__ = 'oauth__tokens'
+
+    id = Column(Integer, primary_key=True)
+    created = Column(DateTime, nullable=False,
+            default=datetime.now)
+    expires = Column(DateTime, nullable=False,
+            default=lambda: datetime.now() + timedelta(days=30))
+    token = Column(Unicode, index=True)
+    refresh_token = Column(Unicode, index=True)
+
+    user_id = Column(Integer, ForeignKey(User.id), nullable=False,
+            index=True)
+
+    client_id = Column(Integer, ForeignKey(OAuthClient_v0.id), nullable=False)
+
+    def __repr__(self):
+        return '<{0} #{1} expires {2} [{3}, {4}]>'.format(
+                self.__class__.__name__,
+                self.id,
+                self.expires.isoformat(),
+                self.user,
+                self.client)
+
+
+class OAuthCode_v0(declarative_base()):
+    __tablename__ = 'oauth__codes'
+
+    id = Column(Integer, primary_key=True)
+    created = Column(DateTime, nullable=False,
+            default=datetime.now)
+    expires = Column(DateTime, nullable=False,
+            default=lambda: datetime.now() + timedelta(minutes=5))
+    code = Column(Unicode, index=True)
+
+    user_id = Column(Integer, ForeignKey(User.id), nullable=False,
+            index=True)
+
+    client_id = Column(Integer, ForeignKey(OAuthClient_v0.id), nullable=False)
+
+
 @RegisterMigration(1, MIGRATIONS)
 def remove_and_replace_token_and_code(db):
     metadata = MetaData(bind=db.bind)
@@ -38,9 +116,9 @@ def remove_and_replace_token_and_code(db):
 
     code_table.drop()
 
-    OAuthClient.__table__.create(db.bind)
-    OAuthUserClient.__table__.create(db.bind)
-    OAuthToken.__table__.create(db.bind)
-    OAuthCode.__table__.create(db.bind)
+    OAuthClient_v0.__table__.create(db.bind)
+    OAuthUserClient_v0.__table__.create(db.bind)
+    OAuthToken_v0.__table__.create(db.bind)
+    OAuthCode_v0.__table__.create(db.bind)
 
     db.commit()