# Path: onix/model.py
# class Moveset(namedtuple('Moveset', ['formes',
#                                      'gender',
#                                      'item',
#                                      'moves',
#                                      'level',
#                                      'happiness'])):
#     """
#     Container comprising a complete description of a specific build's
#     battle-relevant attributes (read: not nickname).
# 
#     Args:
#         formes (:obj:`list` of :obj:`Forme`) : the formes the Pokemon might
#             take over the course of the battle
# 
#             .. note ::
#                 The first forme in this list is considered the Pokemon's
#                 "primary forme." It is the forme the Pokemon will appear in
#                 the first time it appears on the field (making an exception for
#                 orb-holding Groudon and Kyogre who transform immediately into
#                 their Primal formes and do not change back)
# 
#         gender ('m', 'f' or 'u') : the Pokemon's gender ('u' represents "not
#             specified")
#         item (str) : the Pokemon's held item
#         moves (:obj:`list` of :obj:`str`) : the moves the Pokemon knows
#         level (int) : the Pokemon's level
#         happiness (int) : the Pokemon's happiness
# 
#     Note:
#         Nature, IVs and EVs aren't included in this description, since there
#         might be multiple ways to get to the same battle-stats, but they're all
#         functionally equivalent.
# 
#     """
#     pass
# 
# class Forme(namedtuple('Forme', ['species',
#                                  'ability',
#                                  'stats'])):
#     """
#     Container to represent a Pokemon's Forme (that is, the aspects of a moveset
#     that might change when forme changes).
# 
#     Args:
#         species (str) : forme name
#         ability (str) : the Pokemon's ability
#         stats (PokeStats) : the Pokemon's battle stats (that is, not base stats)
#     """
# 
# class BattleInfo(namedtuple('BattleInfo', ['id',
#                                            'format',
#                                            'date',
#                                            'players',
#                                            'slots',
#                                            'turn_length',
#                                            'end_type'])):
#     """
#     Container consisting of metadata for a given battle
# 
#     Args:
#         id (int) : numerical id of the battle, typically found in the name of
#             the log
#         format (str) : the metagame of the battle
#         date (datetime.date) : the date on which the battle occurred
#         players (:obj:`list` of :obj:`Player`) : the battle participants
#         slots (:obj:`list` of `list` of str) : the set IDs for the Pokemon
#             on each player's team. Should have the same length as ``players``
#         turn_length (int) : the number of turns in the battle
#         end_type (str) : how the battle ended (e.g. "normal" or "forfeit")
# 
#     """
#     pass
# 
# class Player(namedtuple('Player', ['id',
#                                    'rating'])):
#     """
#     Container for metadata about a given player/alt
# 
#     Args:
#         id (str) : the player's unique ID
#         rating (dict) : dictionary of player ratings (e.g. Elo, W-L record...).
#             The specifics of what's included in this dict will vary based on
#             the context.
#     """
#     pass
# 
# Path: onix/utilities.py
# def compute_sid(moveset, sanitizer=None):
#     """
#     Computes the Set ID for the given moveset
# 
#     Args:
#         moveset (Moveset): the moveset to compute the SID for
#         sanitizer (:obj:`Sanitizer`, optional): if no sanitizer is provided,
#             ``moveset`` is assumed to be already sanitized. Otherwise, the
#             provided ``Sanitizer`` is used to sanitize the moveset.
# 
#     Returns:
#         str : the corresponding Set ID
# 
#     Examples:
#         >>> from onix.model import PokeStats, Forme, Moveset
#         >>> from onix import utilities
#         >>> moveset = Moveset([Forme('mamoswine','thickfat',
#         ...                          PokeStats(361,394,197,158,156,259))],
#         ...                   'f', 'lifeorb',
#         ...                   ['earthquake', 'iceshard', 'iciclecrash',
#         ...                    'superpower'], 100, 255)
#         >>> print(utilities.compute_sid(moveset)) #doctest: +ELLIPSIS
#         ad9a9fa20...
# 
#     """
#     if sanitizer is not None:
#         moveset = sanitizer.sanitize(moveset)
# 
#     moveset_hash = hashlib.sha512(repr(moveset).encode('utf-8')).hexdigest()
# 
#     # may eventually want to truncate hash, e.g.
#     # moveset_hash = moveset_hash[:16]
# 
#     return moveset_hash
# 
# Path: onix/collection/sinks.py
# class _Sink(with_metaclass(abc.ABCMeta, object)):
# class MovesetSink(_Sink):
# class BattleInfoSink(_Sink):
# class BattleSink(_Sink):
#     def flush(self):
#     def close(self):
#     def __enter__(self):
#     def __exit__(self, *exc):
#     def store_movesets(self, movesets):
#     def store_battle_info(self, battle_info):
#     def store_battle(self, battle):
# 
# Path: onix/backend/sql/schema.py
# def set_sqlite_pragma(dbapi_connection, connection_record):
# def _ignore_insert(conn, element, multiparams, params):
# def create_tables(engine):


import hashlib
from collections import OrderedDict
from future.utils import iteritems
from onix.model import Moveset, Forme, BattleInfo, Player
from onix.utilities import compute_sid
from onix.collection import sinks as _sinks
from onix.backend.sql import schema
        Returns:
            dict : the empty cache
        """
        cache = OrderedDict()
        for table in self.tables:
            cache[table] = []
        return cache

    def add_to_cache(self, inserts):
        """
        Add insert rows to the cache

        Args:
            inserts (`dict`) : the rows to insert, with the keys being the
                tables into which the rows will be inserted

        Returns:
            None
        """
        for table, rows in iteritems(inserts):
            self.cache[table] += rows

    def perform_inserts(self, connection):
        with connection.begin() as transaction:
            for table, rows in iteritems(self.cache):
                if rows:
                    connection.execute(table.insert(), rows)
        self.cache = self._new_cache()



# Path: onix/model.py
# class Moveset(namedtuple('Moveset', ['formes',
#                                      'gender',
#                                      'item',
#                                      'moves',
#                                      'level',
#                                      'happiness'])):
#     """
#     Container comprising a complete description of a specific build's
#     battle-relevant attributes (read: not nickname).
# 
#     Args:
#         formes (:obj:`list` of :obj:`Forme`) : the formes the Pokemon might
#             take over the course of the battle
# 
#             .. note ::
#                 The first forme in this list is considered the Pokemon's
#                 "primary forme." It is the forme the Pokemon will appear in
#                 the first time it appears on the field (making an exception for
#                 orb-holding Groudon and Kyogre who transform immediately into
#                 their Primal formes and do not change back)
# 
#         gender ('m', 'f' or 'u') : the Pokemon's gender ('u' represents "not
#             specified")
#         item (str) : the Pokemon's held item
#         moves (:obj:`list` of :obj:`str`) : the moves the Pokemon knows
#         level (int) : the Pokemon's level
#         happiness (int) : the Pokemon's happiness
# 
#     Note:
#         Nature, IVs and EVs aren't included in this description, since there
#         might be multiple ways to get to the same battle-stats, but they're all
#         functionally equivalent.
# 
#     """
#     pass
# 
# class Forme(namedtuple('Forme', ['species',
#                                  'ability',
#                                  'stats'])):
#     """
#     Container to represent a Pokemon's Forme (that is, the aspects of a moveset
#     that might change when forme changes).
# 
#     Args:
#         species (str) : forme name
#         ability (str) : the Pokemon's ability
#         stats (PokeStats) : the Pokemon's battle stats (that is, not base stats)
#     """
# 
# class BattleInfo(namedtuple('BattleInfo', ['id',
#                                            'format',
#                                            'date',
#                                            'players',
#                                            'slots',
#                                            'turn_length',
#                                            'end_type'])):
#     """
#     Container consisting of metadata for a given battle
# 
#     Args:
#         id (int) : numerical id of the battle, typically found in the name of
#             the log
#         format (str) : the metagame of the battle
#         date (datetime.date) : the date on which the battle occurred
#         players (:obj:`list` of :obj:`Player`) : the battle participants
#         slots (:obj:`list` of `list` of str) : the set IDs for the Pokemon
#             on each player's team. Should have the same length as ``players``
#         turn_length (int) : the number of turns in the battle
#         end_type (str) : how the battle ended (e.g. "normal" or "forfeit")
# 
#     """
#     pass
# 
# class Player(namedtuple('Player', ['id',
#                                    'rating'])):
#     """
#     Container for metadata about a given player/alt
# 
#     Args:
#         id (str) : the player's unique ID
#         rating (dict) : dictionary of player ratings (e.g. Elo, W-L record...).
#             The specifics of what's included in this dict will vary based on
#             the context.
#     """
#     pass
# 
# Path: onix/utilities.py
# def compute_sid(moveset, sanitizer=None):
#     """
#     Computes the Set ID for the given moveset
# 
#     Args:
#         moveset (Moveset): the moveset to compute the SID for
#         sanitizer (:obj:`Sanitizer`, optional): if no sanitizer is provided,
#             ``moveset`` is assumed to be already sanitized. Otherwise, the
#             provided ``Sanitizer`` is used to sanitize the moveset.
# 
#     Returns:
#         str : the corresponding Set ID
# 
#     Examples:
#         >>> from onix.model import PokeStats, Forme, Moveset
#         >>> from onix import utilities
#         >>> moveset = Moveset([Forme('mamoswine','thickfat',
#         ...                          PokeStats(361,394,197,158,156,259))],
#         ...                   'f', 'lifeorb',
#         ...                   ['earthquake', 'iceshard', 'iciclecrash',
#         ...                    'superpower'], 100, 255)
#         >>> print(utilities.compute_sid(moveset)) #doctest: +ELLIPSIS
#         ad9a9fa20...
# 
#     """
#     if sanitizer is not None:
#         moveset = sanitizer.sanitize(moveset)
# 
#     moveset_hash = hashlib.sha512(repr(moveset).encode('utf-8')).hexdigest()
# 
#     # may eventually want to truncate hash, e.g.
#     # moveset_hash = moveset_hash[:16]
# 
#     return moveset_hash
# 
# Path: onix/collection/sinks.py
# class _Sink(with_metaclass(abc.ABCMeta, object)):
# class MovesetSink(_Sink):
# class BattleInfoSink(_Sink):
# class BattleSink(_Sink):
#     def flush(self):
#     def close(self):
#     def __enter__(self):
#     def __exit__(self, *exc):
#     def store_movesets(self, movesets):
#     def store_battle_info(self, battle_info):
#     def store_battle(self, battle):
# 
# Path: onix/backend/sql/schema.py
# def set_sqlite_pragma(dbapi_connection, connection_record):
# def _ignore_insert(conn, element, multiparams, params):
# def create_tables(engine):


# Path: onix/backend/sql/sinks.py
import hashlib
from collections import OrderedDict
from future.utils import iteritems
from onix.model import Moveset, Forme, BattleInfo, Player
from onix.utilities import compute_sid
from onix.collection import sinks as _sinks
from onix.backend.sql import schema

        Returns:
            dict : the empty cache
        """
        cache = OrderedDict()
        for table in self.tables:
            cache[table] = []
        return cache

    def add_to_cache(self, inserts):
        """
        Add insert rows to the cache

        Args:
            inserts (`dict`) : the rows to insert, with the keys being the
                tables into which the rows will be inserted

        Returns:
            None
        """
        for table, rows in iteritems(inserts):
            self.cache[table] += rows

    def perform_inserts(self, connection):
        with connection.begin() as transaction:
            for table, rows in iteritems(self.cache):
                if rows:
                    connection.execute(table.insert(), rows)
        self.cache = self._new_cache()



class MovesetSink(_sinks.MovesetSink):