X-Git-Url: http://git.veekun.com/zzz-pokedex.git/blobdiff_plain/6977ef3de59a5a4ba6c4525a0c5948d93a97b32e..022bbf854bfd867bc2868a5c0c8e8383deacbdd0:/pokedex/db/util.py?ds=inline diff --git a/pokedex/db/util.py b/pokedex/db/util.py new file mode 100644 index 0000000..9131654 --- /dev/null +++ b/pokedex/db/util.py @@ -0,0 +1,123 @@ +"""Helpers for common ways to work with pokedex queries + +These include identifier- and name-based lookup, filtering out base forms +of pokemon, and filtering/ordering by name. +""" + +from sqlalchemy.orm import aliased + +from pokedex.db import tables + +### Getter + +def get(session, table, identifier=None, name=None, id=None, + form_identifier=None, form_name=None, language=None, is_pokemon=None): + """Get one object from the database. + + session: The session to use (from pokedex.db.connect()) + table: The table to select from (such as pokedex.db.tables.Move) + + identifier: Identifier of the object + name: The name of the object + id: The ID number of the object + form_identifier: For pokemon, identifier of the form + form_name: For pokemon, name of the form + + language: A Language to use for name and form_name + is_pokemon: If true, specifies that the table should be treated as a + pokemon table (handling forms specially). If None and table is the + (unaliased) Pokemon, it is set to True. Otherwise, the pokemon forms + aren't handled. + + All conditions must match, so it's not a good idea to specify more than one + of identifier/name/id at once. + + If zero or more than one objects matching the criteria are found, the + appropriate SQLAlchemy exception is raised. + Exception: for pokemon, selects the form base unless form_* is given. + """ + + if is_pokemon is None: + is_pokemon = (table is tables.Pokemon) + + query = session.query(table) + + if identifier is not None: + query = query.filter_by(identifier=identifier) + + if name is not None: + query = filter_name(query, table, name, language) + + if id is not None: + query = query.filter_by(id=id) + + if form_identifier is not None or form_name is not None: + if is_pokemon: + query = query.join(table.unique_form) + if form_identifier is not None: + query = query.filter(tables.PokemonForm.identifier == + form_identifier) + if form_name is not None: + query = filter_name(query, table, form_name, language) + else: + raise ValueError( + "form_identifier and form_name only make sense for pokemon") + elif is_pokemon: + query = filter_base_forms(query) + + return query.one() + +### Helpers + +def filter_name(query, table, name, language): + """Filter a query by name, return the resulting query + + query: The query to filter + table: The table of named objects + name: The name to look for. May be a tuple of alternatives. + language: The language for "name", or None for the session default + """ + if language is None: + query = query.filter(table.name == name) + else: + names_table = table.names_table + query = query.join(names_table) + query = query.filter(names_table.foreign_id == table.id) + query = query.filter(names_table.local_language_id == language.id) + if isinstance(name, tuple): + query = query.filter(names_table.name in name) + else: + query = query.filter(names_table.name == name) + return query + +def filter_base_forms(query): + """Filter only base forms of pokemon, and return the resulting query + """ + query = query.filter(tables.Pokemon.forms.any()) + return query + +def order_by_name(query, table, language=None, *extra_languages): + """Order a query by name. + + query: The query to order + table: Table of the named objects + language: The language to order names by. If None, use the + connection default. + extra_languages: Extra languages to order by, should the translations for + `language` be incomplete (or ambiguous). + + Uses the identifier as a fallback ordering. + """ + if language is None: + query = query.outerjoin(table.names_local) + query = query.order_by(table.names_table.name) + else: + extra_languages = (language, ) + extra_languages + for language in extra_languages: + names_table = aliased(table.names_table) + query = query.outerjoin(names_table) + query = query.filter(names_table.foreign_id == table.id) + query = query.filter(names_table.local_language_id == language.id) + query = query.order_by(names_table.name) + query = query.order_by(table.identifier) + return query