|
|
|
@ -14,20 +14,8 @@ import sqlalchemy.orm
|
|
|
|
# TODO: l o g g i n g
|
|
|
|
# TODO: l o g g i n g
|
|
|
|
HASH_CHUNK_SIZE = 10485760 # 10mb
|
|
|
|
HASH_CHUNK_SIZE = 10485760 # 10mb
|
|
|
|
|
|
|
|
|
|
|
|
db_session = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_db_session_maker = sqlalchemy.orm.sessionmaker()
|
|
|
|
|
|
|
|
_engine = None
|
|
|
|
|
|
|
|
_configured = False
|
|
|
|
|
|
|
|
_SQLBase = sqlalchemy.ext.declarative.declarative_base()
|
|
|
|
_SQLBase = sqlalchemy.ext.declarative.declarative_base()
|
|
|
|
|
|
|
|
|
|
|
|
class MetadataDBSessionException(Exception):
|
|
|
|
|
|
|
|
'''This exception is raised when something goes wrong with a database session.'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _uuidgen():
|
|
|
|
|
|
|
|
return str(uuid.uuid4())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
Metadata ORM classes for SQLAlchemy. For a detailed description of each piece of data, refer to
|
|
|
|
Metadata ORM classes for SQLAlchemy. For a detailed description of each piece of data, refer to
|
|
|
|
metadata/README.md
|
|
|
|
metadata/README.md
|
|
|
|
@ -112,35 +100,35 @@ class Image(_SQLBase):
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class hashdb:
|
|
|
|
|
|
|
|
_engine = None
|
|
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
|
# TODO: db_path's default should be set here, not in frontend.
|
|
|
|
# TODO: I was attempting to avoid writing a class to see if I could, but it is not worth the clunk.
|
|
|
|
def __init__(self, db_path):
|
|
|
|
Rewrite these functions into a class.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def configure(db_path):
|
|
|
|
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
Configure and initialize the database for the entire module.
|
|
|
|
Configure and initialize the database for the entire module.
|
|
|
|
Currently, only SQLite is supported.
|
|
|
|
Currently, only SQLite is supported.
|
|
|
|
|
|
|
|
|
|
|
|
db_path: Path for the SQLite database
|
|
|
|
db_path: Path for the SQLite database
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
_engine = sqlalchemy.create_engine('sqlite:///%s' % db_path)
|
|
|
|
self._engine = sqlalchemy.create_engine('sqlite:///%s' % db_path)
|
|
|
|
|
|
|
|
|
|
|
|
_SQLBase.metadata.create_all(_engine)
|
|
|
|
_SQLBase.metadata.create_all(self._engine)
|
|
|
|
_db_session_maker.configure(bind=_engine)
|
|
|
|
self._session_maker.configure(bind=self._engine)
|
|
|
|
_configured = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def search(session, table_object, **constraints):
|
|
|
|
def search(self, table_object, **constraints):
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
Search the database for entries matching the given 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
|
|
|
|
table_object: SQLAlchemy ORM table object, defined in the file above
|
|
|
|
constraints: key-value pairs to match against specific fields in the database
|
|
|
|
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
|
|
|
|
Note: Currently, only the query.ilike method is supported. This is intended to
|
|
|
|
eventually support the entire range of available filters.
|
|
|
|
eventually support the entire range of available filters.
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with self._get_db_session() as session:
|
|
|
|
|
|
|
|
# TODO: Consider making this return data recursively on items that reference other
|
|
|
|
|
|
|
|
# tables.
|
|
|
|
query = session.query(table_object)
|
|
|
|
query = session.query(table_object)
|
|
|
|
|
|
|
|
|
|
|
|
for key, value in constraints.items():
|
|
|
|
for key, value in constraints.items():
|
|
|
|
@ -152,14 +140,20 @@ def search(session, table_object, **constraints):
|
|
|
|
|
|
|
|
|
|
|
|
return item_list
|
|
|
|
return item_list
|
|
|
|
|
|
|
|
|
|
|
|
@contextlib.contextmanager
|
|
|
|
def import_json(self, json_file):
|
|
|
|
def get_db_session():
|
|
|
|
'''
|
|
|
|
|
|
|
|
Import metadata from a json file.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# json files can be large, but not too large for ram
|
|
|
|
|
|
|
|
# do not exit on invalid metadata, log the error and skip the object
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@contextlib.contextmanager
|
|
|
|
|
|
|
|
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: There's probably a more reliable way of knowing whether the database was configured.
|
|
|
|
|
|
|
|
if not _configured:
|
|
|
|
|
|
|
|
raise MetadataDBSessionException('Tried to get session without configuring a database.')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
session = _db_session_maker()
|
|
|
|
session = sqlalchemy.orm.sessionmaker()
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
yield session
|
|
|
|
yield session
|
|
|
|
|
|
|
|
|
|
|
|
|