Add MediaFile table and related infrastructure.
authorElrond <elrond+mediagoblin.org@samba-tng.org>
Sat, 31 Dec 2011 22:01:34 +0000 (23:01 +0100)
committerElrond <elrond+mediagoblin.org@samba-tng.org>
Wed, 11 Jan 2012 11:19:03 +0000 (12:19 +0100)
- This adds a new SQL table field type for path tuples.
  They're stored as '/' separated unicode strings.

- Uses it to implement a MediaFile table.

- Add relationship and proxy fields on MediaEntry to give a
  nice media_files "view" there.

- Let the converter fill the MediaFile.

mediagoblin/db/sql/convert.py
mediagoblin/db/sql/extratypes.py [new file with mode: 0644]
mediagoblin/db/sql/models.py

index 6698b7672dbe2cf1970498238fd38035a38a846b..88614fd41ff9cdeb7266ffd2d014e8a940ad3990 100644 (file)
@@ -2,7 +2,7 @@ from mediagoblin.init import setup_global_and_app_config, setup_database
 from mediagoblin.db.mongo.util import ObjectId
 
 from mediagoblin.db.sql.models import (Base, User, MediaEntry, MediaComment,
-    Tag, MediaTag)
+    Tag, MediaTag, MediaFile)
 from mediagoblin.db.sql.open import setup_connection_and_db_from_config as \
     sql_connect
 from mediagoblin.db.mongo.open import setup_connection_and_db_from_config as \
@@ -70,6 +70,11 @@ def convert_media_entries(mk_db):
         session.flush()
         add_obj_ids(entry, new_entry)
 
+        for key, value in entry.media_files.iteritems():
+            new_file = MediaFile(name=key, file_path=value)
+            new_file.media_entry = new_entry.id
+            Session.add(new_file)
+
     session.commit()
     session.close()
 
diff --git a/mediagoblin/db/sql/extratypes.py b/mediagoblin/db/sql/extratypes.py
new file mode 100644 (file)
index 0000000..88f556d
--- /dev/null
@@ -0,0 +1,18 @@
+from sqlalchemy.types import TypeDecorator, Unicode
+
+
+class PathTupleWithSlashes(TypeDecorator):
+    "Represents a Tuple of strings as a slash separated string."
+
+    impl = Unicode
+
+    def process_bind_param(self, value, dialect):
+        if value is not None:
+            assert len(value), "Does not support empty lists"
+            value = '/'.join(value)
+        return value
+
+    def process_result_value(self, value, dialect):
+        if value is not None:
+            value = tuple(value.split('/'))
+        return value
index 95821b4f9f9044e1015d0b14712b706eb7471a7e..91092f332fd68ec99e3c5d101ceaf03133e4975b 100644 (file)
@@ -5,7 +5,10 @@ from sqlalchemy import (
     Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey,
     UniqueConstraint)
 from sqlalchemy.orm import relationship
+from sqlalchemy.orm.collections import attribute_mapped_collection
+from sqlalchemy.ext.associationproxy import association_proxy
 
+from mediagoblin.db.sql.extratypes import PathTupleWithSlashes
 from mediagoblin.db.sql.base import GMGTableBase
 from mediagoblin.db.mixin import UserMixin, MediaEntryMixin
 
@@ -65,7 +68,7 @@ class MediaEntry(Base, MediaEntryMixin):
     fail_error = Column(Unicode)
     fail_metadata = Column(UnicodeText)
 
-    queued_media_file = Column(Unicode)
+    queued_media_file = Column(PathTupleWithSlashes)
 
     queued_task_id = Column(Unicode)
 
@@ -75,13 +78,33 @@ class MediaEntry(Base, MediaEntryMixin):
 
     get_uploader = relationship(User)
 
+    media_files_helper = relationship("MediaFile",
+        collection_class=attribute_mapped_collection("name"),
+        cascade="all, delete-orphan"
+        )
+    media_files = association_proxy('media_files_helper', 'file_path',
+        creator=lambda k,v: MediaFile(name=k, file_path=v)
+        )
+
     ## TODO
-    # media_files
     # media_data
     # attachment_files
     # fail_error
 
 
+class MediaFile(Base):
+    __tablename__ = "mediafiles"
+
+    media_entry = Column(
+        Integer, ForeignKey(MediaEntry.id),
+        nullable=False, primary_key=True)
+    name = Column(Unicode, primary_key=True)
+    file_path = Column(PathTupleWithSlashes)
+
+    def __repr__(self):
+        return "<MediaFile %s: %r>" % (self.name, self.file_path)
+
+
 class Tag(Base):
     __tablename__ = "tags"