Add descriptions to new tables
[zzz-pokedex.git] / pokedex / db / tables.py
index 88b206a..89a0efa 100644 (file)
@@ -25,7 +25,9 @@ from sqlalchemy.ext.declarative import (
         declarative_base, declared_attr, DeclarativeMeta,
     )
 from sqlalchemy.ext.associationproxy import association_proxy
-from sqlalchemy.orm import backref, eagerload_all, relation, class_mapper
+from sqlalchemy.orm import (
+        backref, eagerload_all, relation, class_mapper, synonym, mapper,
+    )
 from sqlalchemy.orm.session import Session
 from sqlalchemy.orm.collections import attribute_mapped_collection
 from sqlalchemy.sql import and_
@@ -713,19 +715,32 @@ class MoveFlavorText(TableBase, LanguageSpecific):
 class MoveMeta(TableBase):
     u"""Metadata for move effects, sorta-kinda ripped straight from the game"""
     __tablename__ = 'move_meta'
-    move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
-    meta_category_id = Column(Integer, ForeignKey('move_meta_categories.id'), nullable=False)
-    meta_ailment_id = Column(Integer, ForeignKey('move_meta_ailments.id'), nullable=False)
-    min_hits = Column(Integer, nullable=True, index=True)
-    max_hits = Column(Integer, nullable=True, index=True)
-    min_turns = Column(Integer, nullable=True, index=True)
-    max_turns = Column(Integer, nullable=True, index=True)
-    recoil = Column(Integer, nullable=False, index=True)
-    healing = Column(Integer, nullable=False, index=True)
-    crit_rate = Column(Integer, nullable=False, index=True)
-    ailment_chance = Column(Integer, nullable=False, index=True)
-    flinch_chance = Column(Integer, nullable=False, index=True)
-    stat_chance = Column(Integer, nullable=False, index=True)
+    move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
+        info=dict(description="A numeric ID"))
+    meta_category_id = Column(Integer, ForeignKey('move_meta_categories.id'), nullable=False,
+        info=dict(description="ID of the move category"))
+    meta_ailment_id = Column(Integer, ForeignKey('move_meta_ailments.id'), nullable=False,
+        info=dict(description="ID of the caused ailment"))
+    min_hits = Column(Integer, nullable=True, index=True,
+        info=dict(description="Minimum number of hits per use"))
+    max_hits = Column(Integer, nullable=True, index=True,
+        info=dict(description="Maximum number of hits per use"))
+    min_turns = Column(Integer, nullable=True, index=True,
+        info=dict(description="Minimum number of turns the user is forced to use the move"))
+    max_turns = Column(Integer, nullable=True, index=True,
+        info=dict(description="Maximum number of turns the user is forced to use the move"))
+    recoil = Column(Integer, nullable=False, index=True,
+        info=dict(description="Recoil damage, in percent of damage done"))
+    healing = Column(Integer, nullable=False, index=True,
+        info=dict(description="Healing, in percent of user's max HP"))
+    crit_rate = Column(Integer, nullable=False, index=True,
+        info=dict(description="Critical hit rate bonus"))
+    ailment_chance = Column(Integer, nullable=False, index=True,
+        info=dict(description="Chance to cause an ailment, in percent"))
+    flinch_chance = Column(Integer, nullable=False, index=True,
+        info=dict(description="Chance to cause flinching, in percent"))
+    stat_chance = Column(Integer, nullable=False, index=True,
+        info=dict(description="Chance to cause a stat change, in percent"))
 
 class MoveMetaAilment(TableBase, OfficiallyNamed):
     u"""Common status ailments moves can inflict on a single Pokémon, including
@@ -733,22 +748,29 @@ class MoveMetaAilment(TableBase, OfficiallyNamed):
     """
     __tablename__ = 'move_meta_ailments'
     __singlename__ = 'move_meta_ailment'
-    id = Column(Integer, primary_key=True, nullable=False)
-    identifier = Column(Unicode(24), nullable=False)
+    id = Column(Integer, primary_key=True, nullable=False,
+        info=dict(description="A numeric ID"))
+    identifier = Column(Unicode(24), nullable=False,
+        info=dict(description="An identifier", format='identifier'))
 
 class MoveMetaCategory(TableBase):
     u"""Very general categories that loosely group move effects."""
     __tablename__ = 'move_meta_categories'
     __singlename__ = 'move_meta_category'
-    id = Column(Integer, primary_key=True, nullable=False)
-    description = ProseColumn(Unicode(64), plural='descriptions', nullable=False)
+    id = Column(Integer, primary_key=True, nullable=False,
+        info=dict(description="A numeric ID"))
+    description = ProseColumn(Unicode(64), plural='descriptions', nullable=False,
+        info=dict(description="A description of the category"))
 
 class MoveMetaStatChange(TableBase):
     u"""Stat changes moves (may) make."""
     __tablename__ = 'move_meta_stat_changes'
-    move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
-    stat_id = Column(Integer, ForeignKey('stats.id'), primary_key=True, nullable=False, autoincrement=False)
-    change = Column(Integer, nullable=False, index=True)
+    move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
+        info=dict(description="ID of the move"))
+    stat_id = Column(Integer, ForeignKey('stats.id'), primary_key=True, nullable=False, autoincrement=False,
+        info=dict(description="ID of the stat"))
+    change = Column(Integer, nullable=False, index=True,
+        info=dict(description="Amount of increase/decrease, in stages"))
 
 class MoveTarget(TableBase, UnofficiallyNamed):
     u"""Targetting or "range" of a move, e.g. "Affects all opponents" or "Affects user".
@@ -1327,11 +1349,14 @@ class StatHint(TableBase):
     """
     __tablename__ = 'stat_hints'
     __singlename__ = 'stat_hint'
-    id = Column(Integer, primary_key=True, nullable=False)
-    stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False)
-    gene_mod_5 = Column(Integer, nullable=False, index=True)
+    id = Column(Integer, primary_key=True, nullable=False,
+        info=dict(description=u"A numeric ID"))
+    stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False,
+        info=dict(description=u"ID of the highest stat"))
+    gene_mod_5 = Column(Integer, nullable=False, index=True,
+        info=dict(description=u"Value of the highest stat modulo 5"))
     text = TextColumn(Unicode(24), plural='texts', nullable=False, index=True, unique=True,
-        info=dict(description=u"The English text displayed", official=True, format='plaintext'))
+        info=dict(description=u"The text displayed", official=True, format='plaintext'))
 
 class SuperContestCombo(TableBase):
     u"""Combo of two moves in a Super Contest.
@@ -1770,52 +1795,53 @@ def makeTextTable(object_table, name_plural, name_singular, columns, lazy):
     if safe_name == 'language':
         safe_name = 'lang'
 
-    fields = {
-            safe_name + '_id': Column(Integer,
-                    ForeignKey(object_table.id), primary_key=True, nullable=False,
-                    info=dict(description="ID of the object this table represents")
-                ),
-            '__tablename__': table.__singlename__ + '_' + name_plural,
-            '__singlename__': table.__singlename__ + '_' + name_singular,
-            'is_%s_table' % name_singular: True,
-        }
+    tablename = object_table.__singlename__ + '_' + name_plural
+    singlename = object_table.__singlename__ + '_' + name_singular
 
-    fields.update((name, col) for name, plural, col in columns)
+    class Strings(object):
+        __tablename__ = tablename
+        __singlename__ = singlename
 
-    name = table.__name__ + name_singular.capitalize()
+    for name, plural, column in columns:
+        column.name = name
 
-    # There are some dynamic things that can only be set at class
-    # creation time because of declarative metaclass magic.
-    # So create class dynamically.
-    Strings = type(name, (TableBase, LanguageSpecific), fields)
+    table = Table(tablename, metadata,
+            Column(safe_name + '_id', Integer, ForeignKey(object_table.id),
+                    primary_key=True, nullable=False),
+            Column('language_id', Integer, ForeignKey(Language.id),
+                    primary_key=True, nullable=False),
+            *(column for name, plural, column in columns)
+        )
 
-    # Alias the described thing to 'object', to make meta stuff easier
-    Strings.object_id = getattr(Strings, safe_name + '_id')
+    mapper(Strings, table,
+            properties={
+                    "object_id": synonym(safe_name + '_id'),
+                    "language": relation(
+                            Language,
+                            primaryjoin=table.c.language_id == Language.id,
+                        ),
+                },
+        )
 
     # The relation to the object
-    setattr(table, name_plural, relation(
+    setattr(object_table, name_plural, relation(
             Strings,
-            primaryjoin=(table.id == Strings.object_id),
+            primaryjoin=(object_table.id == Strings.object_id),
             backref=safe_name,
             collection_class=attribute_mapped_collection('language'),
             lazy=lazy,
         ))
-
     Strings.object = getattr(Strings, safe_name)
 
-    Strings.object_table = table
-    setattr(table, name_singular + '_table', Strings)
-
-    Strings.language = relation(
-            Language,
-            primaryjoin=Strings.language_id == Language.id,
-        )
+    # Link the tables themselves, so we can get to them
+    Strings.object_table = object_table
+    setattr(object_table, name_singular + '_table', Strings)
 
     for colname, pluralname, column in columns:
         # Provide a relation with all the names, and an English accessor
         # for backwards compatibility
         def scope(colname, pluralname, column):
-            def get_string(self):
+            def get_strings(self):
                 return dict(
                         (l, getattr(t, colname))
                         for l, t in getattr(self, name_plural).items()
@@ -1823,16 +1849,16 @@ def makeTextTable(object_table, name_plural, name_singular, columns, lazy):
 
             def get_english_string(self):
                 try:
-                    return get_string(self)['en']
+                    return get_strings(self)['en']
                 except KeyError:
                     raise AttributeError(colname)
 
-            setattr(table, pluralname, property(get_string))
-            setattr(table, colname, property(get_english_string))
+            setattr(object_table, pluralname, property(get_strings))
+            setattr(object_table, colname, property(get_english_string))
         scope(colname, pluralname, column)
 
         if colname == 'name':
-            table.name_table = Strings
+            object_table.name_table = Strings
 
     return Strings