You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Lark/hashdb.py

163 lines
5.0 KiB
Python

'''
hashdb.py
'''
import collections
import dataclasses
import hashlib
import sqlite3
import uuid
# TODO: l o g g i n g
HASH_CHUNK_SIZE = 10485760 # 10mb
SQL_AND = ' AND '
SQL_OR = ' OR '
# TODO: Figure out how to do some kind of type checking for these named tuples.
# TODO: Switch these over to using traditional classes.
# TODO: UUID generation/editing is probably best done in here.
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')
def _uuidgen():
return str(uuid.uuid4())
@dataclasses.dataclass
class BaseMetaData:
#TODO: See below
'''
Move the uuid property in here once this bug gets fixed.
https://bugs.python.org/issue36077
Inheriting properties with default values is currently kind of broken.
'''
@dataclasses.dataclass
class PlatformData(BaseMetaData):
name: str
shortcode: str
uuid: str = dataclasses.field(default_factory=_uuidgen)
# TODO: This should go in the eventual romdb class.
def get_file_sha1sum(filename):
sha1sum = hashlib.sha1()
with open(filename, 'rb') as file_contents:
while True:
chunk = file_contents.read(HASH_CHUNK_SIZE)
if not chunk:
break
sha1sum.update(chunk)
return sha1sum.hexdigest()
def _build_sql_constraints(inclusive, constraints):
'''Build an SQL constraint clause out of a dictionary.
inclusive - If True, uses SQL AND operator, otherwise OR will be used.
constraints - A dictionary of arbitrary constraints
returns a tuple containing the appropriately formatted SQL string and a list of parameters
'''
if constraints == {}:
return ('', [])
if inclusive:
logical_separator = SQL_AND
else:
logical_separator = SQL_OR
sql_constraint_string = 'WHERE '
sql_parameter_list = []
for key, value in constraints.items():
sql_constraint_string += '%s=?%s' % (key, logical_separator)
sql_parameter_list.append(value)
# Trim off the last ', '
sql_constraint_string = sql_constraint_string[0:-len(logical_separator)]
return (sql_constraint_string, sql_parameter_list)
class MetadataDB:
def __init__(self, db_path):
'''
If db file does not exist, create it and create necessary tables.
Either way, create a connection object.
'''
# TODO: This process needs real error handling.
self._connection = sqlite3.connect(db_path)
with self._connection:
self._connection.execute('CREATE TABLE IF NOT EXISTS images (uuid PRIMARY KEY, '
'sha1sum UNIQUE NOT NULL, filename NOT NULL, release_group);')
self._connection.execute('CREATE TABLE IF NOT EXISTS release_groups (UUID PRIMARY KEY, '
'name NOT NULL, platform NOT NULL);')
self._connection.execute('CREATE TABLE IF NOT EXISTS platforms (UUID PRIMARY KEY, '
'name NOT NULL, shortcode UNIQUE NOT NULL);')
# TODO: Add DAT import support.
print('Database initialized.')
def add_image(self, image_data):
pass
def update_image(self, image_data):
pass
def remove_image(self, image_data):
pass
def add_release_group(self, release_group_data):
pass
def update_release_group(self, release_group_data):
pass
def remove_release_group(self, release_group_data):
pass
def add_platform(self, platform_data):
''' Add a platform shortcode to the database. '''
values = list(dataclasses.asdict(platform_data).values())
print(values)
with self._connection:
self._connection.execute('INSERT INTO platforms VALUES (?, ?, ?);', values)
def update_platform(self, platform_data):
pass
# TODO: Switch this to use more generic constraints language
def remove_platform(self, platform_shortcode):
with self._connection:
self._connection.execute('DELETE FROM platforms WHERE shortcode=?;', platform_shortcode)
def search_platforms(self, inclusive=True, **constraints):
'''Search for platforms, given the parameters. '''
sql_where_clause, sql_parameters = _build_sql_constraints(inclusive, constraints)
platform_data_list = []
with self._connection:
cursor = self._connection.cursor()
sql_query = 'SELECT * FROM platforms %s;' % sql_where_clause
cursor.execute(sql_query, sql_parameters)
rows = cursor.fetchall()
for row in rows:
platform_data = PlatformData(*row)
platform_data_list.append(platform_data)
return platform_data_list
def add_dat(self, dat_data):
pass
def update_dat(self, dat_data):
pass
def remove_dat(self, dat_data):
pass