Added metadata relationships to ORM classes. This file is feature-complete!

dev
Emily Frost 6 years ago
parent ef15d9f579
commit e12c9059d7
No known key found for this signature in database
GPG Key ID: FD1FA524668FB1FA

61
lark

@ -132,5 +132,66 @@ if action_object == 'platform':
with metadatadb.get_db_session() as session: with metadatadb.get_db_session() as session:
print(metadatadb.search(session, metadatadb.Platform)) print(metadatadb.search(session, metadatadb.Platform))
elif action_object == 'release-group':
if action == 'add':
properties = _kwargs_parse(sys.argv[3:])
release_group = metadatadb.ReleaseGroup(name=properties['name'])
with metadatadb.get_db_session() as session:
if properties['platform']:
platform = metadatadb.search(session, metadatadb.Platform,
shortcode=properties['platform'])[0]
release_group.platform = platform
session.add(release_group)
if action == 'list':
# TODO: Filter support is exclusively limited to SQLAlchemy's filter.ilike function. Figure
# out a good way to include other filters.
print('Listing release groups.')
filters = _kwargs_parse(sys.argv[3:])
with metadatadb.get_db_session() as session:
print(metadatadb.search(session, metadatadb.ReleaseGroup, **filters))
elif action == 'remove':
constraints = sys.argv[3:]
filters = _kwargs_parse(sys.argv[3:])
with metadatadb.get_db_session() as session:
release_groups = metadatadb.search(session, metadatadb.ReleaseGroup, **filters)
for release_group in release_groups:
print('Removing %s.' % release_group.name)
session.delete(release_group)
elif action_object == 'image':
if action == 'add':
properties = _kwargs_parse(sys.argv[3:])
image = metadatadb.Image(filename=properties['filename'],
sha1sum=properties['sha1sum'])
with metadatadb.get_db_session() as session:
if properties['release-group']:
release_group = metadatadb.search(session, metadatadb.ReleaseGroup,
name=properties['release-group'])[0]
image.release_group = release_group
session.add(image)
if action == 'list':
# TODO: Filter support is exclusively limited to SQLAlchemy's filter.ilike function. Figure
# out a good way to include other filters.
print('Listing release groups.')
filters = _kwargs_parse(sys.argv[3:])
with metadatadb.get_db_session() as session:
print(metadatadb.search(session, metadatadb.Image, **filters))
elif action == 'remove':
constraints = sys.argv[3:]
filters = _kwargs_parse(sys.argv[3:])
with metadatadb.get_db_session() as session:
release_groups = metadatadb.search(session, metadatadb.Image, **filters)
for image in release_groups:
print('Removing %s.' % image.name)
session.delete(image)
else: else:
print('Unknown object.') print('Unknown object.')

@ -4,6 +4,7 @@ metadatadb.py
Everything needed to interact with the metadata database; namely SQL ORM objects, a context 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. generator for the actual database, and a handful of convenience functions.
''' '''
# TODO: Rename file to metadata.py
import contextlib import contextlib
import collections import collections
import hashlib import hashlib
@ -18,6 +19,7 @@ HASH_CHUNK_SIZE = 10485760 # 10mb
_db_session_maker = sqlalchemy.orm.sessionmaker() _db_session_maker = sqlalchemy.orm.sessionmaker()
_engine = None _engine = None
# TODO: Support DAT credit, DAT filenames, and checking DAT completeness.
DatData = collections.namedtuple('DatData', 'UUID, name, website, version, image_list') DatData = collections.namedtuple('DatData', 'UUID, name, website, version, image_list')
@ -26,6 +28,7 @@ def _uuidgen():
_SQLBase = sqlalchemy.ext.declarative.declarative_base() _SQLBase = sqlalchemy.ext.declarative.declarative_base()
# TODO: Rename Image concept to "Release".
class Image(_SQLBase): class Image(_SQLBase):
'''SQLAlchemy ORM class for ROM image metadata.''' '''SQLAlchemy ORM class for ROM image metadata.'''
# TODO: Split filenames into more meaningful metadata. # TODO: Split filenames into more meaningful metadata.
@ -35,12 +38,14 @@ class Image(_SQLBase):
uuid = sqlalchemy.Column(sqlalchemy.String, nullable=False, default=_uuidgen) uuid = sqlalchemy.Column(sqlalchemy.String, nullable=False, default=_uuidgen)
sha1sum = sqlalchemy.Column(sqlalchemy.String, unique=True, nullable=False) sha1sum = sqlalchemy.Column(sqlalchemy.String, unique=True, nullable=False)
filename = sqlalchemy.Column(sqlalchemy.String, unique=True, nullable=False) filename = sqlalchemy.Column(sqlalchemy.String, unique=True, nullable=False)
release_group_id = sqlalchemy.Column(sqlalchemy.Integer,
sqlalchemy.ForeignKey('release_groups.id'))
# TODO: Add many-to-one relationship to release groups. release_group = sqlalchemy.orm.relationship('ReleaseGroup', back_populates='images')
def __repr__(self): def __repr__(self):
return 'ROM Image: id: %s, uuid: %s, sha1sum: %s, filename: %s' % (self.id, self.uuid, return 'ROM Image: id: %s, uuid: %s, sha1sum: %s, filename: %s, release-group: %s' % (
self.sha1sum, self.filename) self.id, self.uuid, self.sha1sum, self.filename, self.release_group.name)
class ReleaseGroup(_SQLBase): class ReleaseGroup(_SQLBase):
'''SQLAlchemy ORM class for release group metadata.''' '''SQLAlchemy ORM class for release group metadata.'''
@ -49,11 +54,14 @@ class ReleaseGroup(_SQLBase):
primary_key=True) primary_key=True)
uuid = sqlalchemy.Column(sqlalchemy.String, nullable=False, default=_uuidgen) uuid = sqlalchemy.Column(sqlalchemy.String, nullable=False, default=_uuidgen)
name = sqlalchemy.Column(sqlalchemy.String, unique=True, nullable=False) name = sqlalchemy.Column(sqlalchemy.String, unique=True, nullable=False)
# TODO: Add many-to-one relationship to platforms. platform_id = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey('platforms.id'))
platform = sqlalchemy.orm.relationship('Platform', back_populates='release_groups')
images = sqlalchemy.orm.relationship('Image', back_populates='release_group')
def __repr__(self): def __repr__(self):
return 'Release Group: id: %s, uuid: %s, name: %s' % (self.id, self.uuid, return 'Release Group: id: %s, uuid: %s, name: %s, platform:%s' % (self.id, self.uuid,
self.name) self.name, self.platform.fullname)
class Platform(_SQLBase): class Platform(_SQLBase):
@ -65,6 +73,9 @@ class Platform(_SQLBase):
fullname = sqlalchemy.Column(sqlalchemy.String, nullable=False) fullname = sqlalchemy.Column(sqlalchemy.String, nullable=False)
shortcode = sqlalchemy.Column(sqlalchemy.String, unique=True, nullable=False) shortcode = sqlalchemy.Column(sqlalchemy.String, unique=True, nullable=False)
release_groups = sqlalchemy.orm.relationship('ReleaseGroup', order_by=ReleaseGroup.id,
back_populates='platform')
def __repr__(self): def __repr__(self):
return 'Platform: id: %s, uuid: %s, fullname: %s, shortcode: %s' % (self.id, self.uuid, return 'Platform: id: %s, uuid: %s, fullname: %s, shortcode: %s' % (self.id, self.uuid,
self.fullname, self.shortcode) self.fullname, self.shortcode)
@ -94,6 +105,8 @@ def configure(db_path):
_SQLBase.metadata.create_all(_engine) _SQLBase.metadata.create_all(_engine)
_db_session_maker.configure(bind=_engine) _db_session_maker.configure(bind=_engine)
# TODO: Passing the session object is a little clunky. Maybe there's a way to infer it somehow?
# Maybe setting a _session class variable?
def search(session, table_object, **constraints): def search(session, table_object, **constraints):
''' '''
Search the database for entries matching the given constraints. Search the database for entries matching the given constraints.
@ -118,11 +131,14 @@ def search(session, table_object, **constraints):
@contextlib.contextmanager @contextlib.contextmanager
def get_db_session(): def get_db_session():
'''Get a SQLAlchemy database session with a proper context object. ''' '''Get a SQLAlchemy database session with a proper context object. '''
# TODO: Raise an exception if _db_session_maker() isn't configured.
session = _db_session_maker() session = _db_session_maker()
try: try:
yield session yield session
except: except:
# TODO: Decide which exceptions to handle/eat here and which ones belong in UI.
# This one is okay to put off until you start really building UI.
session.rollback() session.rollback()
raise raise
else: else:

Loading…
Cancel
Save