Add index=True for some columns.
[mediagoblin.git] / mediagoblin / db / sql / models.py
index 699dbf3353be622f60f1f9c24c52a85e2f0de7c0..8d198fd691664bf20a7ae58ef82aafa3f6fa2af5 100644 (file)
@@ -20,18 +20,21 @@ TODO: indexes on foreignkeys, where useful.
 
 
 import datetime
+import sys
 
 from sqlalchemy import (
     Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey,
-    UniqueConstraint)
+    UniqueConstraint, PrimaryKeyConstraint, SmallInteger)
 from sqlalchemy.orm import relationship
 from sqlalchemy.orm.collections import attribute_mapped_collection
 from sqlalchemy.sql.expression import desc
 from sqlalchemy.ext.associationproxy import association_proxy
+from sqlalchemy.util import memoized_property
 
 from mediagoblin.db.sql.extratypes import PathTupleWithSlashes, JSONEncoded
 from mediagoblin.db.sql.base import Base, DictReadAttrProxy
 from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, MediaCommentMixin
+from mediagoblin.db.sql.base import Session
 
 # It's actually kind of annoying how sqlalchemy-migrate does this, if
 # I understand it right, but whatever.  Anyway, don't remove this :P
@@ -58,7 +61,7 @@ class User(Base, UserMixin):
     TODO: We should consider moving some rarely used fields
     into some sort of "shadow" table.
     """
-    __tablename__ = "users"
+    __tablename__ = "core__users"
 
     id = Column(Integer, primary_key=True)
     username = Column(Unicode, nullable=False, unique=True)
@@ -84,13 +87,14 @@ class MediaEntry(Base, MediaEntryMixin):
     """
     TODO: Consider fetching the media_files using join
     """
-    __tablename__ = "media_entries"
+    __tablename__ = "core__media_entries"
 
     id = Column(Integer, primary_key=True)
-    uploader = Column(Integer, ForeignKey('users.id'), nullable=False)
+    uploader = Column(Integer, ForeignKey(User.id), nullable=False, index=True)
     title = Column(Unicode, nullable=False)
     slug = Column(Unicode)
-    created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+    created = Column(DateTime, nullable=False, default=datetime.datetime.now,
+        index=True)
     description = Column(UnicodeText) # ??
     media_type = Column(Unicode, nullable=False)
     state = Column(Unicode, default=u'unprocessed', nullable=False)
@@ -118,6 +122,15 @@ class MediaEntry(Base, MediaEntryMixin):
         creator=lambda k, v: MediaFile(name=k, file_path=v)
         )
 
+    attachment_files_helper = relationship("MediaAttachmentFile",
+        cascade="all, delete-orphan",
+        order_by="MediaAttachmentFile.created"
+        )
+    attachment_files = association_proxy("attachment_files_helper", "dict_view",
+        creator=lambda v: MediaAttachmentFile(
+            name=v["name"], filepath=v["filepath"])
+        )
+
     tags_helper = relationship("MediaTag",
         cascade="all, delete-orphan"
         )
@@ -127,7 +140,6 @@ class MediaEntry(Base, MediaEntryMixin):
 
     ## TODO
     # media_data
-    # attachment_files
     # fail_error
 
     _id = SimpleFieldAlias("id")
@@ -159,26 +171,106 @@ class MediaEntry(Base, MediaEntryMixin):
         if media is not None:
             return media.url_for_self(urlgen)
 
+    #@memoized_property
+    @property
+    def media_data(self):
+        session = Session()
+
+        return session.query(self.media_data_table).filter_by(
+            media_entry=self.id).first()
+
+    def media_data_init(self, **kwargs):
+        """
+        Initialize or update the contents of a media entry's media_data row
+        """
+        session = Session()
+
+        media_data = session.query(self.media_data_table).filter_by(
+            media_entry=self.id).first()
+
+        # No media data, so actually add a new one
+        if not media_data:
+            media_data = self.media_data_table(
+                **kwargs)
+            session.add(media_data)
+        # Update old media data
+        else:
+            for field, value in kwargs.iteritems():
+                setattr(media_data, field, value)
+
+    @memoized_property
+    def media_data_table(self):
+        # TODO: memoize this
+        models_module = self.media_type + '.models'
+        __import__(models_module)
+        return sys.modules[models_module].DATA_MODEL
+
+
+class FileKeynames(Base):
+    """
+    keywords for various places.
+    currently the MediaFile keys
+    """
+    __tablename__ = "core__file_keynames"
+    id = Column(Integer, primary_key=True)
+    name = Column(Unicode, unique=True)
+
+    def __repr__(self):
+        return "<FileKeyname %r: %r>" % (self.id, self.name)
+
+    @classmethod
+    def find_or_new(cls, name):
+        t = cls.query.filter_by(name=name).first()
+        if t is not None:
+            return t
+        return cls(name=name)
+
 
 class MediaFile(Base):
     """
     TODO: Highly consider moving "name" into a new table.
     TODO: Consider preloading said table in software
     """
-    __tablename__ = "mediafiles"
+    __tablename__ = "core__mediafiles"
 
     media_entry = Column(
         Integer, ForeignKey(MediaEntry.id),
-        nullable=False, primary_key=True)
-    name = Column(Unicode, primary_key=True)
+        nullable=False)
+    name_id = Column(SmallInteger, ForeignKey(FileKeynames.id), nullable=False)
     file_path = Column(PathTupleWithSlashes)
 
+    __table_args__ = (
+        PrimaryKeyConstraint('media_entry', 'name_id'),
+        {})
+
     def __repr__(self):
         return "<MediaFile %s: %r>" % (self.name, self.file_path)
 
+    name_helper = relationship(FileKeynames, lazy="joined", innerjoin=True)
+    name = association_proxy('name_helper', 'name',
+        creator=FileKeynames.find_or_new
+        )
+
+
+class MediaAttachmentFile(Base):
+    __tablename__ = "core__attachment_files"
+
+    id = Column(Integer, primary_key=True)
+    media_entry = Column(
+        Integer, ForeignKey(MediaEntry.id),
+        nullable=False)
+    name = Column(Unicode, nullable=False)
+    filepath = Column(PathTupleWithSlashes)
+    created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+
+    @property
+    def dict_view(self):
+        """A dict like view on this object"""
+        return DictReadAttrProxy(self)
+
 
 class Tag(Base):
-    __tablename__ = "tags"
+    __tablename__ = "core__tags"
 
     id = Column(Integer, primary_key=True)
     slug = Column(Unicode, nullable=False, unique=True)
@@ -195,13 +287,13 @@ class Tag(Base):
 
 
 class MediaTag(Base):
-    __tablename__ = "media_tags"
+    __tablename__ = "core__media_tags"
 
     id = Column(Integer, primary_key=True)
     media_entry = Column(
         Integer, ForeignKey(MediaEntry.id),
-        nullable=False)
-    tag = Column(Integer, ForeignKey('tags.id'), nullable=False)
+        nullable=False, index=True)
+    tag = Column(Integer, ForeignKey(Tag.id), nullable=False, index=True)
     name = Column(Unicode)
     # created = Column(DateTime, nullable=False, default=datetime.datetime.now)
 
@@ -228,12 +320,12 @@ class MediaTag(Base):
 
 
 class MediaComment(Base, MediaCommentMixin):
-    __tablename__ = "media_comments"
+    __tablename__ = "core__media_comments"
 
     id = Column(Integer, primary_key=True)
     media_entry = Column(
-        Integer, ForeignKey('media_entries.id'), nullable=False)
-    author = Column(Integer, ForeignKey('users.id'), nullable=False)
+        Integer, ForeignKey(MediaEntry.id), nullable=False, index=True)
+    author = Column(Integer, ForeignKey(User.id), nullable=False)
     created = Column(DateTime, nullable=False, default=datetime.datetime.now)
     content = Column(UnicodeText, nullable=False)
 
@@ -243,7 +335,8 @@ class MediaComment(Base, MediaCommentMixin):
 
 
 MODELS = [
-    User, MediaEntry, Tag, MediaTag, MediaComment]
+    User, MediaEntry, Tag, MediaTag, MediaComment, MediaFile, FileKeynames,
+    MediaAttachmentFile]
 
 
 ######################################################
@@ -254,7 +347,7 @@ MODELS = [
 ######################################################
 
 class MigrationData(Base):
-    __tablename__ = "migrations"
+    __tablename__ = "core__migrations"
 
     name = Column(Unicode, primary_key=True)
     version = Column(Integer, nullable=False, default=0)