# XXX: Check if "gametext" is set correctly everywhere
import collections
+from functools import partial
from sqlalchemy import Column, ForeignKey, MetaData, PrimaryKeyConstraint, Table, UniqueConstraint
from sqlalchemy.ext.declarative import (
backref, compile_mappers, eagerload_all, relation, class_mapper, synonym, mapper,
)
from sqlalchemy.orm.session import Session, object_session
-from sqlalchemy.orm.collections import attribute_mapped_collection
-from sqlalchemy.ext.associationproxy import association_proxy
+from sqlalchemy.orm.interfaces import AttributeExtension
+from sqlalchemy.orm.collections import attribute_mapped_collection, MappedCollection, collection, collection_adapter
+from sqlalchemy.ext.associationproxy import _AssociationDict, association_proxy
from sqlalchemy.sql import and_
-from sqlalchemy.sql.expression import ColumnOperators
+from sqlalchemy.sql.expression import ColumnOperators, bindparam
from sqlalchemy.schema import ColumnDefault
from sqlalchemy.types import *
from inspect import isclass
-from pokedex.db import markdown
+from pokedex.db import markdown, multilang
# A list of all table classes will live in table_classes
table_classes = []
"""A column that will appear in the corresponding _text table"""
+### Need Language first, to create the partial() below
+
+class Language(TableBase):
+ u"""A language the Pokémon games have been transleted into
+ """
+ __tablename__ = 'languages'
+ __singlename__ = 'language'
+ id = Column(Integer, primary_key=True, nullable=False,
+ info=dict(description="A numeric ID"))
+ iso639 = Column(Unicode(2), nullable=False,
+ info=dict(description="The two-letter code of the country where this language is spoken. Note that it is not unique.", format='identifier'))
+ iso3166 = Column(Unicode(2), nullable=False,
+ info=dict(description="The two-letter code of the language. Note that it is not unique.", format='identifier'))
+ identifier = Column(Unicode(16), nullable=False,
+ info=dict(description="An identifier", format='identifier'))
+ official = Column(Boolean, nullable=False, index=True,
+ info=dict(description=u"True iff games are produced in the language."))
+ order = Column(Integer, nullable=True,
+ info=dict(description=u"Order for sorting in foreign name lists."))
+ name = TextColumn(Unicode(16), nullable=False, index=True, plural='names',
+ info=dict(description="The name", format='plaintext', official=True))
+
+create_translation_table = partial(multilang.create_translation_table, language_class=Language)
+
### The actual tables
class Ability(TableBase):
info=dict(description="An identifier", format='identifier'))
generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
info=dict(description="The ID of the generation this ability was introduced in", detail=True))
- effect = ProseColumn(markdown.MarkdownColumn(5120), plural='effects', nullable=False,
- info=dict(description="A detailed description of this ability's effect", format='markdown'))
- short_effect = ProseColumn(markdown.MarkdownColumn(255), plural='short_effects', nullable=False,
- info=dict(description="A short summary of this ability's effect", format='markdown'))
- name = TextColumn(Unicode(24), nullable=False, index=True, plural='names',
- info=dict(description="The name", format='plaintext', official=True))
+
+create_translation_table('ability_texts', Ability, 'names',
+ name = Column(Unicode(24), nullable=False, index=True,
+ info=dict(description="The name", format='plaintext', official=True)),
+)
+create_translation_table('ability_prose', Ability, 'prose',
+ effect = Column(markdown.MarkdownColumn(5120), nullable=False,
+ info=dict(description="A detailed description of this ability's effect", format='markdown')),
+ short_effect = Column(markdown.MarkdownColumn(255), nullable=False,
+ info=dict(description="A short summary of this ability's effect", format='markdown')),
+)
class AbilityChangelog(TableBase):
"""History of changes to abilities across main game versions."""
name = TextColumn(Unicode(16), nullable=False, index=True, plural='names',
info=dict(description="The name", format='plaintext', official=True))
-class Language(TableBase):
- u"""A language the Pokémon games have been transleted into
- """
- __tablename__ = 'languages'
- __singlename__ = 'language'
- id = Column(Integer, primary_key=True, nullable=False,
- info=dict(description="A numeric ID"))
- iso639 = Column(Unicode(2), nullable=False,
- info=dict(description="The two-letter code of the country where this language is spoken. Note that it is not unique.", format='identifier'))
- iso3166 = Column(Unicode(2), nullable=False,
- info=dict(description="The two-letter code of the language. Note that it is not unique.", format='identifier'))
- identifier = Column(Unicode(16), nullable=False,
- info=dict(description="An identifier", format='identifier'))
- official = Column(Boolean, nullable=False, index=True,
- info=dict(description=u"True iff games are produced in the language."))
- order = Column(Integer, nullable=True,
- info=dict(description=u"Order for sorting in foreign name lists."))
- name = TextColumn(Unicode(16), nullable=False, index=True, plural='names',
- info=dict(description="The name", format='plaintext', official=True))
-
- # Languages compare equal to its identifier, so a dictionary of
- # translations, with a Language as the key, can be indexed by the identifier
- def __eq__(self, other):
- try:
- return (
- self is other or
- self.identifier == other or
- self.identifier == other.identifier
- )
- except AttributeError:
- return NotImplemented
-
- def __ne__(self, other):
- return not (self == other)
-
- def __hash__(self):
- return hash(self.identifier)
-
class Location(TableBase):
u"""A place in the Pokémon world
"""
info=dict(description="ID of the move's Contest effect"))
super_contest_effect_id = Column(Integer, ForeignKey('super_contest_effects.id'), nullable=True,
info=dict(description="ID of the move's Super Contest effect"))
- name = TextColumn(Unicode(24), nullable=False, index=True, plural='names',
+
+create_translation_table('move_texts', Move, 'names',
+ name = Column(Unicode(24), nullable=False, index=True,
info=dict(description="The name", format='plaintext', official=True))
+)
+
class MoveChangelog(TableBase):
"""History of changes to moves across main game versions."""
info=dict(description=u"The height of the Pokémon, in decimeters (tenths of a meter)"))
weight = Column(Integer, nullable=False,
info=dict(description=u"The weight of the Pokémon, in tenths of a kilogram (decigrams)"))
- species = TextColumn(Unicode(16), nullable=False, plural='species_names',
- info=dict(description=u'The short flavor text, such as "Seed" or "Lizard"; usually affixed with the word "Pokémon"',
- official=True, format='plaintext'))
color_id = Column(Integer, ForeignKey('pokemon_colors.id'), nullable=False,
info=dict(description=u"ID of this Pokémon's Pokédex color, as used for a gimmick search function in the games."))
pokemon_shape_id = Column(Integer, ForeignKey('pokemon_shapes.id'), nullable=True,
info=dict(description=u"Set iff the species exhibits enough sexual dimorphism to have separate sets of sprites in Gen IV and beyond."))
order = Column(Integer, nullable=False, index=True,
info=dict(description=u"Order for sorting. Almost national order, except families and forms are grouped together."))
- name = TextColumn(Unicode(20), nullable=False, index=True, plural='names',
- info=dict(description="The name", format='plaintext', official=True))
### Stuff to handle alternate Pokémon forms
else:
return None
+create_translation_table('pokemon_texts', Pokemon, 'names',
+ name = Column(Unicode(20), nullable=False, index=True,
+ info=dict(description="The name", format='plaintext', official=True)),
+ species = Column(Unicode(16), nullable=False,
+ info=dict(description=u'The short flavor text, such as "Seed" or "Lizard"; usually affixed with the word "Pokémon"',
+ official=True, format='plaintext')),
+)
+
class PokemonAbility(TableBase):
u"""Maps an ability to a Pokémon that can have it
"""
Ability.all_pokemon = relation(Pokemon,
secondary=PokemonAbility.__table__,
order_by=Pokemon.order,
- back_populates='all_abilities',
+ #back_populates='all_abilities',
)
Ability.pokemon = relation(Pokemon,
secondary=PokemonAbility.__table__,
PokemonAbility.is_dream == False
),
order_by=Pokemon.order,
- back_populates='abilities',
+ #back_populates='abilities',
)
Ability.dream_pokemon = relation(Pokemon,
secondary=PokemonAbility.__table__,
PokemonAbility.is_dream == True
),
order_by=Pokemon.order,
- back_populates='dream_ability',
+ #back_populates='dream_ability',
)
AbilityChangelog.changed_in = relation(VersionGroup, backref='ability_changelog')
EvolutionChain.growth_rate = relation(GrowthRate, backref='evolution_chains')
EvolutionChain.baby_trigger_item = relation(Item, backref='evolution_chains')
-EvolutionChain.pokemon = relation(Pokemon, order_by=Pokemon.order, back_populates='evolution_chain')
+EvolutionChain.pokemon = relation(Pokemon, order_by=Pokemon.order)#, back_populates='evolution_chain')
Experience.growth_rate = relation(GrowthRate, backref='experience_table')
Move.super_contest_combo_next = association_proxy('super_contest_combo_first', 'second')
Move.super_contest_combo_prev = association_proxy('super_contest_combo_second', 'first')
Move.target = relation(MoveTarget, backref='moves')
-Move.type = relation(Type, back_populates='moves')
+Move.type = relation(Type)#, back_populates='moves')
MoveChangelog.changed_in = relation(VersionGroup, backref='move_changelog')
MoveChangelog.move_effect = relation(MoveEffect, backref='move_changelog')
NaturePokeathlonStat.pokeathlon_stat = relation(PokeathlonStat, backref='nature_effects')
Pokedex.region = relation(Region, backref='pokedexes')
-Pokedex.version_groups = relation(VersionGroup, order_by=VersionGroup.id, back_populates='pokedex')
+Pokedex.version_groups = relation(VersionGroup, order_by=VersionGroup.id)#, back_populates='pokedex')
Pokemon.all_abilities = relation(Ability,
secondary=PokemonAbility.__table__,
Pokemon.egg_groups = relation(EggGroup, secondary=PokemonEggGroup.__table__,
order_by=PokemonEggGroup.egg_group_id,
backref=backref('pokemon', order_by=Pokemon.order))
-Pokemon.evolution_chain = relation(EvolutionChain, back_populates='pokemon')
+Pokemon.evolution_chain = relation(EvolutionChain)#, back_populates='pokemon')
Pokemon.child_pokemon = relation(Pokemon,
primaryjoin=Pokemon.id==PokemonEvolution.from_pokemon_id,
secondary=PokemonEvolution.__table__,
Pokemon.stats = relation(PokemonStat, backref='pokemon', order_by=PokemonStat.stat_id.asc())
Pokemon.types = relation(Type, secondary=PokemonType.__table__,
order_by=PokemonType.slot.asc(),
- back_populates='pokemon')
+ )#back_populates='pokemon')
PokemonDexNumber.pokedex = relation(Pokedex)
Type.damage_class = relation(MoveDamageClass, backref='types')
Type.pokemon = relation(Pokemon, secondary=PokemonType.__table__,
order_by=Pokemon.order,
- back_populates='types')
+ )#back_populates='types')
Type.moves = relation(Move, back_populates='type', order_by=Move.id)
Version.version_group = relation(VersionGroup, back_populates='versions')
default_lang = u'en'
-def makeTextTable(foreign_table_class, table_suffix_plural, table_suffix_singular, columns, lazy):
+def makeTextTable(foreign_table_class, table_suffix_plural, table_suffix_singular, columns, lazy, Language=Language):
# With "Language", we'd have two language_id. So, rename one to 'lang'
foreign_key_name = foreign_table_class.__singlename__
if foreign_key_name == 'language':
# one by one without the DB complaining about missing values
column.default = ColumnDefault(u'')
- table = Table(table_name, metadata,
+ table = Table(table_name, foreign_table_class.__table__.metadata,
Column(foreign_key_name + '_id', Integer, ForeignKey(foreign_table_class.id),
primary_key=True, nullable=False),
Column('language_id', Integer, ForeignKey(Language.id),
foreign_key_name: relation(foreign_table_class,
primaryjoin=(foreign_table_class.id == table.c[foreign_key_name + "_id"]),
backref=backref(table_suffix_plural,
- collection_class=attribute_mapped_collection('language'),
+ collection_class=attribute_mapped_collection('_language_identifier'),
lazy=lazy,
),
),