diff --git a/metadatadb.py b/metadatadb.py index 8ef6a00..2e92f1f 100644 --- a/metadatadb.py +++ b/metadatadb.py @@ -1,5 +1,8 @@ ''' metadatadb.py + +Everything needed to interact with the metadata database; namely SQL ORM objects, a context +generator for the actual database, and a handful of convenience functions. ''' import contextlib import collections @@ -15,8 +18,6 @@ HASH_CHUNK_SIZE = 10485760 # 10mb _db_session_maker = sqlalchemy.orm.sessionmaker() _engine = None -ImageData = collections.namedtuple('ImageData', 'UUID, sha1sum, filename, release_group') -ReleaseGroupData = collections.namedtuple('ReleaseGroupData', 'UUID, name, platform') DatData = collections.namedtuple('DatData', 'UUID, name, website, version, image_list') @@ -25,7 +26,38 @@ def _uuidgen(): _SQLBase = sqlalchemy.ext.declarative.declarative_base() +class Image(_SQLBase): + '''SQLAlchemy ORM class for ROM image metadata.''' + # TODO: Split filenames into more meaningful metadata. + __tablename__ = 'images' + id = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.Sequence('image_id_sequence'), + primary_key=True) + uuid = sqlalchemy.Column(sqlalchemy.String, nullable=False, default=_uuidgen) + sha1sum = sqlalchemy.Column(sqlalchemy.String, unique=True, nullable=False) + filename = sqlalchemy.Column(sqlalchemy.String, unique=True, nullable=False) + + # TODO: Add many-to-one relationship to release groups. + + def __repr__(self): + return 'ROM Image: id: %s, uuid: %s, sha1sum: %s, filename: %s' % (self.id, self.uuid, + self.sha1sum, self.filename) + +class ReleaseGroup(_SQLBase): + '''SQLAlchemy ORM class for release group metadata.''' + __tablename__ = 'release_groups' + id = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.Sequence('image_id_sequence'), + primary_key=True) + uuid = sqlalchemy.Column(sqlalchemy.String, nullable=False, default=_uuidgen) + name = sqlalchemy.Column(sqlalchemy.String, unique=True, nullable=False) + # TODO: Add many-to-one relationship to platforms. + + def __repr__(self): + return 'Release Group: id: %s, uuid: %s, name: %s' % (self.id, self.uuid, + self.name) + + class Platform(_SQLBase): + '''SQLAlchemy ORM class for platform metadata.''' __tablename__ = 'platforms' id = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.Sequence('platform_id_sequence'), primary_key=True) @@ -37,6 +69,7 @@ class Platform(_SQLBase): return 'Platform: id: %s, uuid: %s, fullname: %s, shortcode: %s' % (self.id, self.uuid, self.fullname, self.shortcode) + # TODO: This should go in the eventual romdb class. def get_file_sha1sum(filename): sha1sum = hashlib.sha1() @@ -50,12 +83,27 @@ def get_file_sha1sum(filename): return sha1sum.hexdigest() def configure(db_path): + ''' + Configure and initialize the database for the entire module. + Currently, only SQLite is supported. + + db_path: Path for the SQLite database + ''' _engine = sqlalchemy.create_engine('sqlite:///%s' % db_path) _SQLBase.metadata.create_all(_engine) _db_session_maker.configure(bind=_engine) -def search(session, table_object, inclusive=True, **constraints): +def search(session, table_object, **constraints): + ''' + Search the database for entries matching the given constraints. + + session: SQLAlchemy session, presumably from get_db_session + table_object: SQLAlchemy ORM table object, defined in the file above + constraints: key-value pairs to match against specific fields in the database + Note: Currently, only the query.ilike method is supported. This is intended to + eventually support the entire range of available filters. + ''' query = session.query(table_object) for key, value in constraints.items(): @@ -69,6 +117,7 @@ def search(session, table_object, inclusive=True, **constraints): @contextlib.contextmanager def get_db_session(): + '''Get a SQLAlchemy database session with a proper context object. ''' session = _db_session_maker() try: yield session