Files
Artemis/artemis/utils/sql_utils.py
2024-06-15 12:01:33 +02:00

418 lines
13 KiB
Python

import os
import sqlite3
from PySide6.QtCore import QUrl
from operator import itemgetter
from datetime import datetime
from contextlib import closing
from artemis.utils.constants import Query, Constants
from artemis.utils.generic_utils import format_frequency
from artemis.utils.path_utils import DATA_DIR
class Database():
""" General superclass for SQLite DB manipulation.
Foreign keys are activated (otherwise disabled by default for compatibility purposes)
"""
def __init__(self, sql_path):
self.sql_path = sql_path
def execute(self, query, parameters=None, last_rowid=False):
""" Open a connection, execute the given query with optional parameters and close the connection.
In the case of a SELECT query, returns the results as a fetchall().
If last_rowid == True, this function returns a tuple with the result of the fetchall() and
the latest modified row id of the current connection.
"""
with closing(sqlite3.connect(self.sql_path, check_same_thread=False)) as conn:
conn.execute('PRAGMA foreign_keys = ON;')
curs = conn.cursor()
if parameters:
curs.execute(query, parameters)
else:
curs.execute(query)
conn.commit()
if last_rowid:
result = (curs.fetchall(), curs.lastrowid)
else:
result = curs.fetchall()
return result
################################## MARK: >>> DATABASE <<<
class ArtemisDatabase(Database):
""" General CRUD class for SQLite DB manipulation.
Foreign keys are activated (otherwise disabled by default for compatibility purposes)
"""
def __init__(self, db_dir_name):
self.db_dir_name = db_dir_name
self.db_dir = DATA_DIR / db_dir_name
self.sql_path = self.db_dir / Constants.SQL_NAME
self.media_dir = self.db_dir / 'media'
super().__init__(self.sql_path)
self.name = None
self.date = None
self.version = None
self.editable = None
self.all_signals = None
self.all_modulation = None
self.all_location = None
self.all_category_labels = None
self.filtered_signals = None
self.stats = {}
def load(self):
self._select_info()
self._select_all()
self._select_all_modulation()
self._select_all_location()
self._select_all_category_labels()
self._select_stats()
def _select_info(self):
""" Load the DB meta INFO from the table 'info'
"""
result = self.execute(Query.SELECT_INFO)[0]
self.name = result[0]
self.date = result[1]
self.version = result[2]
self.editable = result[3]
def _select_all(self):
""" Load a list of tuple for all signals. Each tuple (representing a signal)
contains the SIG_ID and the NAME of the signal
"""
self.all_signals = self.execute(Query.SELECT_ALL_SIGNALS)
keys = ('SIG_ID', 'name', 'description')
result = [dict(zip(keys, values)) for values in self.all_signals]
self.all_signals = result
def _select_all_modulation(self):
self.all_modulation = self.execute(Query.SELECT_ALL_MODULATION)
self.all_modulation = [{'value': item[0]} for item in self.all_modulation]
def _select_all_location(self):
self.all_location = self.execute(Query.SELECT_ALL_LOCATION)
self.all_location = [{'value': item[0]} for item in self.all_location]
def _select_all_category_labels(self):
self.all_category_labels = self.execute(Query.SELECT_ALL_CAT_LABELS)
self.all_category_labels = [{'clb_id': item[0], 'value': item[1]} for item in self.all_category_labels]
def _select_stats(self):
tot_docs = self.execute(Query.SELECT_STAT_DOCS)[0][0]
tot_images = self.execute(Query.SELECT_STAT_IMAGES)[0][0]
tot_audio = self.execute(Query.SELECT_STAT_AUDIO)[0][0]
self.stats['documents'] = tot_docs
self.stats['images'] = tot_images
self.stats['audio'] = tot_audio
self.stats['signals'] = len(self.all_signals)
def select_by_filter(self, filter_query):
matching_sig_ids = self.execute(filter_query)
sig_ids = ",".join(str(num[0]) for num in matching_sig_ids)
self.all_signals = self.execute(Query.SELECT_SIG_ID.format(sig_ids))
keys = ('SIG_ID', 'name', 'description')
result = [dict(zip(keys, values)) for values in self.all_signals]
self.all_signals = result
def create(self, name):
""" Create new db in the data folder.
The name of folder containing the new db has a unique id as name (db_dir_name).
"""
meta = [name, datetime.now(), 1, 1]
os.makedirs(self.db_dir)
os.makedirs(self.media_dir)
self.execute(Query.CREATE_INFO)
self.execute(Query.INSERT_INFO, meta)
self.execute(Query.CREATE_SIGNALS)
self.execute(Query.CREATE_CATEGORY)
self.execute(Query.CREATE_CATEGORY_LABELS)
self.execute(Query.CREATE_FREQUENCY)
self.execute(Query.CREATE_BANDWIDTH)
self.execute(Query.CREATE_MODULATION)
self.execute(Query.CREATE_MODE)
self.execute(Query.CREATE_LOCATION)
self.execute(Query.CREATE_ACF)
self.execute(Query.CREATE_DOCUMENTS)
self.execute(Query.CREATE_VIEW_FREQ)
self.execute(Query.CREATE_VIEW_BAND)
def rename(self, name):
self.execute(Query.RENAME_DB, [name])
def insert_category_label(self, value):
self.execute(Query.INSERT_CATEGORY_LABEL, [value])
def update_category_label(self, clb_id, value):
self.execute(Query.UPDATE_CATEGORY_LABEL, [value, clb_id])
def delete_category_label(self, clb_id):
self.execute(Query.DELETE_CATEGORY_LABEL, [clb_id])
################################## MARK: >>> SIGNAL <<<
class ArtemisSignal():
""" Main class of the object signal
"""
def __init__(self, loaded_db):
self.db = loaded_db
self.sig_id = None
self.name = None
self.description = None
self.url = None
self.category = None
self.frequency = None
self.bandwidth = None
self.modulation = None
self.mode = None
self.location = None
self.acf = None
self.documents = None
self.spectrum_path = None
self.audio_path = None
def load(self, sig_id):
self.sig_id = sig_id
self._select_signals()
self._select_category()
self._select_frequency()
self._select_bandwidth()
self._select_modulation()
self._select_mode()
self._select_location()
self._select_acf()
self.select_documents()
def generate_dic(self):
dic = {
'name': self.name,
'description': self.description,
'url': self.url,
'category': self.category,
'frequency': self.frequency,
'bandwidth': self.bandwidth,
'modulation': self.modulation,
'mode': self.mode,
'location': self.location,
'acf': self.acf,
'spectrum_path': self.spectrum_path,
'audio_path': self.audio_path,
'all_category': self.db.all_category_labels
}
return dic
################################## MARK: SELECT Methods
def _select_signals(self):
signal = self.db.execute(Query.SELECT_SIGNAL, [self.sig_id])[0]
self.name = signal[0]
self.description = signal[1]
self.url = signal[2]
def _select_category(self):
self.category = self.db.execute(Query.SELECT_CATEGORY, [self.sig_id])
self.category = [list(x) for x in self.category]
def _select_frequency(self):
result = self.db.execute(Query.SELECT_FREQUENCY, [self.sig_id])
sorted_list = sorted(result, key=itemgetter(1))
self.frequency = [list(x) + [format_frequency(x[1])] for x in sorted_list]
def _select_bandwidth(self):
result = self.db.execute(Query.SELECT_BANDWIDTH, [self.sig_id])
sorted_list = sorted(result, key=itemgetter(1))
self.bandwidth = [list(x) + [format_frequency(x[1])] for x in sorted_list]
def _select_acf(self):
self.acf = self.db.execute(Query.SELECT_ACF, [self.sig_id])
self.acf = [list(x) for x in self.acf]
def _select_modulation(self):
self.modulation = self.db.execute(Query.SELECT_MODULATION, [self.sig_id])
self.modulation = [list(x) for x in self.modulation]
def _select_mode(self):
self.mode = self.db.execute(Query.SELECT_MODE, [self.sig_id])
self.mode = [list(x) for x in self.mode]
def _select_location(self):
self.location = self.db.execute(Query.SELECT_LOCATION, [self.sig_id])
self.location = [list(x) for x in self.location]
def select_documents(self):
self.documents = self.db.execute(Query.SELECT_DOCUMENTS, [self.sig_id])
default_spectrum = [doc for doc in self.documents if doc[4] == 'Image' and doc[5] == 1]
default_audio = [doc for doc in self.documents if doc[4] == 'Audio' and doc[5] == 1]
if default_spectrum != []:
default_spectrum_filename = '{}.{}'.format(str(default_spectrum[0][0]), default_spectrum[0][1])
self.spectrum_path = self.db.media_dir / default_spectrum_filename
self.spectrum_path = QUrl.fromLocalFile(self.spectrum_path.resolve())
else:
self.spectrum_path = 'qrc:///images/spectrum_not_available.svg'
if default_audio != []:
default_audio_filename = '{}.{}'.format(str(default_audio[0][0]), default_audio[0][1])
self.audio_path = self.db.media_dir / default_audio_filename
self.audio_path = QUrl.fromLocalFile(self.audio_path.resolve())
else:
self.audio_path = ''
################################## MARK: UPDATE Methods
def update_signal(self, sig_id, value, description):
self.db.execute(Query.UPDATE_SIGNAL, [value, description, sig_id])
def update_frequency(self, freq_id, value, description):
self.db.execute(Query.UPDATE_FREQUENCY, [value, description, freq_id])
def update_bandwidth(self, band_id, value, description):
self.db.execute(Query.UPDATE_BANDWIDTH, [value, description, band_id])
def update_modulation(self, modu_id, value, description):
self.db.execute(Query.UPDATE_MODULATION, [value, description, modu_id])
def update_mode(self, mode_id, value, description):
self.db.execute(Query.UPDATE_MODE, [value, description, mode_id])
def update_acf(self, acf_id, value, description):
self.db.execute(Query.UPDATE_ACF, [value, description, acf_id])
def update_location(self, loc_id, value, description):
self.db.execute(Query.UPDATE_LOCATION, [value, description, loc_id])
def update_documents(self, doc_id, name, description, type, is_preview):
self.db.execute(Query.UPDATE_DOCUMENTS, [name, description, type, is_preview, doc_id])
################################## MARK: INSERT Methods
def insert_signal(self, value, description):
self.db.execute(Query.INSERT_SIGNAL, [value, description])
def insert_frequency(self, value, description):
self.db.execute(Query.INSERT_FREQUENCY, [self.sig_id, value, description])
def insert_bandwidth(self, value, description):
self.db.execute(Query.INSERT_BANDWIDTH, [self.sig_id,value, description])
def insert_modulation(self, value, description):
self.db.execute(Query.INSERT_MODULATION, [self.sig_id,value, description])
def insert_mode(self, value, description):
self.db.execute(Query.INSERT_MODE, [self.sig_id,value, description])
def insert_acf(self, value, description):
self.db.execute(Query.INSERT_ACF, [self.sig_id,value, description])
def insert_location(self, value, description):
self.db.execute(Query.INSERT_LOCATION, [self.sig_id,value, description])
def insert_category(self, clb_id):
self.db.execute(Query.INSERT_CATEGORY, [self.sig_id, clb_id])
def insert_document(self, doc_lst):
row_id = self.db.execute(Query.INSERT_DOCUMENTS, [self.sig_id] + doc_lst[1:], True)[1]
return row_id
################################## MARK: DELETE Methods
def delete_signal(self):
self.db.execute(Query.DELETE_SIGNAL, [self.sig_id])
def delete_frequency(self, freq_id):
self.db.execute(Query.DELETE_FREQUENCY, [freq_id])
def delete_bandwidth(self, band_id):
self.db.execute(Query.DELETE_BANDWIDTH, [band_id])
def delete_modulation(self, modu_id):
self.db.execute(Query.DELETE_MODULATION, [modu_id])
def delete_mode(self, mode_id):
self.db.execute(Query.DELETE_MODE, [mode_id])
def delete_acf(self, acf_id):
self.db.execute(Query.DELETE_ACF, [acf_id])
def delete_location(self, loc_id):
self.db.execute(Query.DELETE_LOCATION, [loc_id])
def delete_document(self, doc_id):
self.db.execute(Query.DELETE_DOCUMENT, [doc_id])
def delete_category(self, cat_id):
self.db.execute(Query.DELETE_CATEGORY, [cat_id])