From b5e226bc3a3467b3f3ee9b90826d4df238f547b7 Mon Sep 17 00:00:00 2001 From: Peery Date: Tue, 11 May 2021 23:17:11 +0200 Subject: [PATCH] Updated DB backend for new schemas Update the DB backend to work with an updated schema. Also fixed a few UI bugs caused by that. --- ArtNet/artnet_manager.py | 2 +- ArtNet/db/db_adapter.py | 241 +++++++++++------- .../tag_select_dialog/tag_select_dialog.py | 2 +- ArtNet/gui/window.py | 17 +- 4 files changed, 158 insertions(+), 104 deletions(-) diff --git a/ArtNet/artnet_manager.py b/ArtNet/artnet_manager.py index c5b4bab..5c3b29b 100644 --- a/ArtNet/artnet_manager.py +++ b/ArtNet/artnet_manager.py @@ -131,7 +131,7 @@ class ArtNetManager: if len(result) != 0: # tag is implied by some other tag continue - result = self.db_connection.get_tag_aliases(tag) + result = self.db_connection.get_tag_aliases_by_name(tag) if len(result) != 0: # tag is already tagged by an alias continue diff --git a/ArtNet/db/db_adapter.py b/ArtNet/db/db_adapter.py index c43d4a3..c5c4d4f 100644 --- a/ArtNet/db/db_adapter.py +++ b/ArtNet/db/db_adapter.py @@ -149,10 +149,10 @@ class DBAdapter: presence = self.get_presence(name, domain) d = {"name": name, "domain": domain, "artist": artist_ID, "link": link} if len(presence) == 0: # presence does not exist yet - self.db_cursor.execute("INSERT INTO presence (name, domain, artist, link) " + + self.db_cursor.execute("INSERT INTO presence (name, domain, artist_ID, link) " + "VALUES (%(name)s, %(domain)s, %(artist)s, %(link)s)", d) else: # presence exists, update it - self.db_cursor.execute("UPDATE presence SET artist = %(artist)s, link = %(link)s" + + self.db_cursor.execute("UPDATE presence SET artist_ID = %(artist)s, link = %(link)s" + "WHERE name = %(name)s and domain = %(domain)s", d) self.db.commit() @@ -176,7 +176,7 @@ class DBAdapter: :return: """ d = {"name": name, "domain": domain} - self.db_cursor.execute("SELECT name, domain, artist, link FROM presence " + + self.db_cursor.execute("SELECT name, domain, artist_ID, link FROM presence " + "WHERE name = %(name)s and domain = %(domain)s", d) rows = self.db_cursor.fetchall() @@ -239,6 +239,42 @@ class DBAdapter: self.db.commit() + def get_category_by_ID(self, id: int): + """ + Queries the database for the category by its ID + :param id: + :return: (id, "name") + """ + d = {"id": id} + self.db_cursor.execute("SELECT category_id, name FROM tag_category WHERE category_id = %(id)s", d) + + r = self.db_cursor.fetchall() + if len(r) == 0: + return None + + nr = [] + for i in range(len(r[0])): + if isinstance(r[0][i], str): + nr.append(r[0][i].strip()) + else: + nr.append(r[0][i]) + + return nr + + def get_category_by_name(self, name: str): + """ + Queries the database for the category by its name + :return: + """ + d = {"name": name} + self.db_cursor.execute("SELECT category_id, name FROM tag_category WHERE name = %(name)s", d) + + r = self.db_cursor.fetchall() + if len(r) == 0: + return None + + return r[0] + def get_artist(self, ID: int): """ Queries the database for the artist (not presence) and returns the result @@ -381,13 +417,13 @@ class DBAdapter: Search a list of presences fitting the (name, domain) fuzzy. :param name: :param domain: - :param all_if_empty: + :param all_if_empty: return all presences (or a large selection) if an empty name and domain is given :return: """ if all_if_empty and (name is None or len(name) == 0) and (domain is None or len(domain) == 0): - self.db_cursor.execute("SELECT name, domain, artist FROM presence") + self.db_cursor.execute("SELECT name, domain, artist_id FROM presence") else: - self.db_cursor.execute("SELECT name, domain, artist FROM presence WHERE LOWER(name) LIKE LOWER('%{0}%')".format(name) + + self.db_cursor.execute("SELECT name, domain, artist_id FROM presence WHERE LOWER(name) LIKE LOWER('%{0}%')".format(name) + " AND domain LIKE '%{0}%'".format(domain)) rows = self.db_cursor.fetchall() @@ -444,9 +480,9 @@ class DBAdapter: :return: """ if all_if_empty and len(name) == 0: - self.db_cursor.execute("SELECT name, description, category FROM tag") + self.db_cursor.execute("SELECT name, description, category_id FROM tag") else: - self.db_cursor.execute("SELECT name, description, category FROM tag WHERE LOWER(name) LIKE LOWER('%{0}%')".format(name)) + self.db_cursor.execute("SELECT name, description, category_id FROM tag WHERE LOWER(name) LIKE LOWER('%{0}%')".format(name)) rows = self.db_cursor.fetchall() new_rows = [] @@ -455,8 +491,10 @@ class DBAdapter: for j in range(len(rows[i])): if rows[i][j] is None: new_rows[i].append("") - else: + elif isinstance(rows[i][j], str): new_rows[i].append(rows[i][j].strip()) + else: + new_rows[i].append(rows[i][j]) return new_rows @@ -486,136 +524,176 @@ class DBAdapter: aliases = [] if implications is None: implications = [] - d = {"name": name, "description": description, "category": category} - self.db_cursor.execute("INSERT INTO tag (name, description, category) " + - "VALUES (LOWER(%(name)s), %(description)s, %(category)s)", d) + category_id = self.get_category_by_name(category)[0] + d = {"name": name, "description": description, "category_id": category_id} + self.db_cursor.execute("INSERT INTO tag (name, description, category_id) " + + "VALUES (LOWER(%(name)s), %(description)s, %(category_id)s)", d) for alias in aliases: - self.add_alias(name, alias) + self.add_alias_by_name(name, alias) for implicant in implications: - self.add_implication(name, implicant) + self.add_implication_by_name(name, implicant) self.db.commit() - def edit_tag(self, name: str, description: str, aliases: list=None, implications: list=None, category: str = None, - old_tag: str = None): + def edit_tag(self, tag_id: int, name: str, description: str, aliases: list = None, implications: list = None, + category_id: int = None): """ Edit a tag with the new given data + :param tag_id: tag id to uniquely identify the tag :param name: unique tag name to apply edits to (distinct from old_tag) :param description: new description to apply, set to None to omit :param aliases: list of tag names to be the alias of this tag, set to None to omit :param implications: list of tag names to be implied by this tag, set to None to omit - :param category: - :param old_tag: old tag name from which to transfer all data + :param category_id: :return: """ name = name.strip().lower() d = { + "id": tag_id, "name": name, "description": description, "alias": aliases, "implications": implications, - "category": category, + "category_id": category_id, } - if old_tag is not None and len(old_tag) > 0: - # tag name changed, need to transfer all data and remove old tag - old_tag = self.get_tag_by_name(old_tag) - d["ID"] = old_tag[0][-1] - self.db_cursor.execute("UPDATE tag SET name = %(name)s WHERE tag_ID = %(ID)s", d) - - if description is not None: - self.db_cursor.execute("UPDATE tag SET description = %(description)s, category = %(category)s " + - "WHERE name = %(name)s", d) + self.db_cursor.execute("UPDATE tag SET description = %(description)s, category_id = %(category_id)s, name = %(name)s WHERE tag_ID = %(id)s", d) if aliases is not None: - old_aliases = self.get_tag_aliases(name) + old_aliases = self.get_tag_aliases_by_ID(tag_id) for alias in aliases: if alias in old_aliases: # is this already set? continue - self.add_alias(name, alias) + self.add_alias_by_name(name, alias) for old_alias in old_aliases: if old_alias not in aliases: # got to delete an alias? - self.remove_alias(name, old_alias) + self.remove_alias_by_name(name, old_alias) if implications is not None: old_implicants = self.get_tag_implications(name) for implicant in implications: if implicant in old_implicants: # is this already set? continue - self.add_implication(name, implicant) + self.add_implication_by_name(name, implicant) for old_implicant in old_implicants: if old_implicant not in implications: # got to delete an implicant? - self.remove_implication(name, old_implicant) + self.remove_implication_by_name(name, old_implicant) - def add_alias(self, name: str, alias: str): + def add_alias_by_name(self, name: str, alias: str): """ Add the alias pair to the database :param name: :param alias: :return: """ - d = { - "name": self.get_tag_ID(name), - "alias": self.get_tag_ID(alias) - } - self.db_cursor.execute("INSERT INTO tag_alias (tag1, tag2) VALUES (%(name)s, %(alias)s)", d) + self.add_alias_by_ID(self.get_tag_ID(name), self.get_tag_ID(alias)) - def remove_alias(self, name: str, alias: str): + def add_alias_by_ID(self, tag1: int, tag2: int): + """ + Add the alias pair to the database + :return: + """ + d = { + "tag1": tag1, + "tag2": tag2 + } + self.db_cursor.execute("INSERT INTO tag_alias (tag1, tag2) VALUES (%(tag1)s, %(tag2)s)", d) + self.db.commit() + + def remove_alias_by_ID(self, tag1: int, tag2: int): + """ + Remove alias pair from the database + :param tag1: + :param tag2: + :return: + """ + d = { + "tag1": tag1, + "tag2": tag2 + } + self.db_cursor.execute("DELETE FROM tag_alias WHERE (tag1 = %(tag1)s and tag2 = %(tag2)s) or " + + "(tag1 = %(tag2)s and tag2 = %(tag1)s)", d) + self.db.commit() + + def remove_alias_by_name(self, name: str, alias: str): """ Remove alias pair from the database :param name: :param alias: :return: """ - d = { - "ID": self.get_tag_ID(name), - "alias": self.get_tag_ID(alias) - } - self.db_cursor.execute("DELETE FROM tag_alias WHERE (tag1 = %(ID)s and tag2 = %(alias)s) " + - "or (tag1 = %(alias)s and tag2 = %(ID)s)", d) + self.remove_alias_by_ID(self.get_tag_ID(name), self.get_tag_ID(alias)) - def add_implication(self, name: str, implicant: str): + def add_implication_by_ID(self, tag_id: int, implicant: int): + """ + Add the implication to the database + :param tag_id: + :param implicant: + :return: + """ + d = { + "tag": tag_id, + "implicant": implicant + } + self.db_cursor.execute("INSERT INTO tag_implication (root_tag, implicate) VALUES (%(tag)s, %(implicant)s)", + d) + self.db.commit() + + + def add_implication_by_name(self, name: str, implicant: str): """ Add the implication to the database :param name: :param implicant: :return: """ + self.add_implication_by_ID(self.get_tag_ID(name), self.get_tag_ID(implicant)) + + def remove_implication_by_ID(self, tag: int, implicant: int): + """ + Remove the implication pair from the database + :param tag: + :param implicant: + :return: + """ d = { - "name": self.get_tag_ID(name), - "implicant": self.get_tag_ID(implicant) + "tag": tag, + "implicant": implicant } - self.db_cursor.execute("INSERT INTO tag_implication (root_tag, implicate) VALUES (%(name)s, %(implicant)s)", - d) + self.db_cursor.execute("DELETE FROM tag_implication WHERE root_tag = %(name)s " + + "and implicate = %(implicant)s", d) self.db.commit() - def remove_implication(self, name: str, implicant: str): + def remove_implication_by_name(self, name: str, implicant: str): """ Remove the implication pair from the database :param name: :param implicant: :return: """ - d = {"name": self.get_tag_ID(name), - "implicant": self.get_tag_ID(implicant)} - self.db_cursor.execute("DELETE FROM tag_implication WHERE root_tag = %(name)s " + - "and implicate = %(implicant)s", d) - self.db.commit() + self.remove_implication_by_ID(self.get_tag_ID(name), self.get_tag_ID(implicant)) - def remove_tag(self, name: str): + def remove_tag_by_ID(self, tag: int): """ Remove the given tag from the database - :param str: + :param tag: :return: """ - d = {"name": name} - self.db_cursor.execute("DELETE FROM tag WHERE name = %(name)s", d) - + d = {"tag": tag} + self.db_cursor.execute("DELETE FROM tag WHERE tag_id = %(tag)s", d) self.db.commit() + def remove_tag_by_name(self, name: str): + """ + Remove the given tag from the database + :param name: + :return: + """ + self.remove_tag_by_ID(self.get_tag_ID(name)) + def get_tag_ID(self, name: str) -> int: """ Get the tag ID by querying it by its unique name @@ -623,14 +701,14 @@ class DBAdapter: :return: """ d = {"name": name} - self.db_cursor.execute("SELECT tag_ID, name FROM tag where LOWER(name) = LOWER(%(name)s)", d) + self.db_cursor.execute("SELECT tag_ID FROM tag where LOWER(name) = LOWER(%(name)s)", d) rows = [] for row in self.db_cursor.fetchall(): rows.append(row[0]) if len(rows) > 1: - exit(1) # something went horribly horribly wrong! + raise Exception("Found multiple tags by the same name!") elif len(rows) == 0: return None @@ -645,7 +723,7 @@ class DBAdapter: :return: Returns the tag's name, description, category, tag ID """ d = {"name": name} - self.db_cursor.execute("SELECT name, description, category, tag_ID FROM tag where LOWER(name) = LOWER(%(name)s)", d) + self.db_cursor.execute("SELECT name, description, category_id, tag_ID FROM tag where LOWER(name) = LOWER(%(name)s)", d) rows = [] for row in self.db_cursor.fetchall(): @@ -669,11 +747,11 @@ class DBAdapter: :return: Returns the tag's ID, name, description, category """ d = {"ID": ID} - self.db_cursor.execute("SELECT tag_ID, name, description, category FROM tag where tag_ID = %(ID)s", d) + self.db_cursor.execute("SELECT tag_ID, name, description, category_id FROM tag where tag_ID = %(ID)s", d) return self.db_cursor.fetchall() - def get_tag_aliases(self, name: str) -> list: + def get_tag_aliases_by_name(self, name: str) -> list: """ Search for the tag's aliases and the tag's aliases :param name: @@ -690,7 +768,7 @@ class DBAdapter: def get_tag_aliases_by_ID(self, tag_ID: int) -> list: """ Search for the tag's aliases and the tag's aliases - :param name: + :param tag_ID: :return: List of tag IDs that are aliases of this one """ marked = [] @@ -707,7 +785,7 @@ class DBAdapter: marked.remove(tag_ID) return marked - def get_all_tag_implications(self, name: str) -> list: + def get_all_tag_implications_by_name(self, name: str) -> list: """ Search for the tag's implications and those that are implied by them. :param name: @@ -826,28 +904,3 @@ class DBAdapter: raise Exception("Something went terribly wrong!") return r - - -if __name__ == "__main__": - db = DBAdapter(user="artnet_editor", password="G606Rm9sFEXe6wfTLxVu", - database="artnet", host="localhost", port=5432) - - search = 'Ajin/66699b4e41f533982db1766e8f72494a.gif2222' - print("Art search result:", search, db.get_art_by_path('Ajin/66699b4e41f533982db1766e8f72494a.gif')) - - search = "tag" - print("Fuzzy Search Result:", search, db.search_fuzzy_tag(search)) - - search = "tag1" - print("Search Result:", search, db.get_tag_by_name(search)) - - search = "tag1" - print("Alias Search Result:", search, db.get_tag_aliases(search)) - - search = "tag1" - print("Implication Search Result:", search, db.get_tag_implications(search)) - - target = "tag1" - db.edit_tag(target, "new description! ;D", aliases=["tag1_alias"], implications=["tag1_implicated"]) - print("Editing:", target, db.get_tag_by_name(target), db.get_tag_aliases(target), db.get_tag_implications(target)) - diff --git a/ArtNet/gui/dialogs/tag_select_dialog/tag_select_dialog.py b/ArtNet/gui/dialogs/tag_select_dialog/tag_select_dialog.py index a762aad..d5814d2 100644 --- a/ArtNet/gui/dialogs/tag_select_dialog/tag_select_dialog.py +++ b/ArtNet/gui/dialogs/tag_select_dialog/tag_select_dialog.py @@ -72,6 +72,6 @@ class TagSelectDialog(QtWidgets.QDialog): "description": tag[1], "aliases": self.parent.get_tag_aliases(tag[0]), "implications": self.parent.get_tag_implications(tag[0]), - "category": tag[2] + "category_id": tag[2] } return tag_data diff --git a/ArtNet/gui/window.py b/ArtNet/gui/window.py index 16b6c09..bf9d025 100644 --- a/ArtNet/gui/window.py +++ b/ArtNet/gui/window.py @@ -396,7 +396,7 @@ class Window(QtWidgets.QMainWindow): :param name: :return: """ - return self.__main.db_connection.get_tag_aliases(name) + return self.__main.db_connection.get_tag_aliases_by_name(name) def get_tag_implications(self, name: str) -> list: """ @@ -465,12 +465,12 @@ class Window(QtWidgets.QMainWindow): implied_tags = [] for x in self.curr_tags: # collect all implied tags into a list - implied_tags += self.__main.db_connection.get_all_tag_implications(x) + implied_tags += self.__main.db_connection.get_all_tag_implications_by_name(x) self.set_implied_list(implied_tags) self.curr_tag_aliases = list() for tag in tags+implied_tags: - self.curr_tag_aliases += self.__main.db_connection.get_tag_aliases(tag) + self.curr_tag_aliases += self.__main.db_connection.get_tag_aliases_by_name(tag) self.data_changed = True @@ -815,7 +815,7 @@ class Window(QtWidgets.QMainWindow): if confirmation_reply == QtWidgets.QMessageBox.No: return - self.__main.db_connection.remove_tag(tag["name"]) + self.__main.db_connection.remove_tag_by_name(tag["name"]) self.on_tag_search_change() def force_edit_tag_dialog(self, name: str): @@ -858,7 +858,7 @@ class Window(QtWidgets.QMainWindow): if tag is None or len(tag) == 0: return - tag['aliases'] = self.__main.db_connection.get_tag_aliases(tag["name"]) + tag['aliases'] = self.__main.db_connection.get_tag_aliases_by_name(tag["name"]) tag['implications'] = self.__main.db_connection.get_tag_implications(tag["name"]) edit_dialog = TagModifyDialog(self, create_tag=False) @@ -868,7 +868,7 @@ class Window(QtWidgets.QMainWindow): edit_dialog.alias_selection = tag["aliases"] edit_dialog.set_selected_implicated_tags(tag["implications"], set_checked=True) edit_dialog.implication_selection = tag["implications"] - edit_dialog.category_selection = tag["category"] + edit_dialog.category_selection = self.__main.db_connection.get_category_by_ID(tag["category_id"])[1] edit_dialog.set_all_categories() tag_data = edit_dialog.exec_() @@ -879,9 +879,10 @@ class Window(QtWidgets.QMainWindow): if "old_tag_name" not in tag_data.keys(): tag_data["old_tag_name"] = None - self.__main.db_connection.edit_tag(name=tag_data["name"], description=tag_data["description"], + self.__main.db_connection.edit_tag(tag_id=tag["ID"], + name=tag_data["name"], description=tag_data["description"], aliases=tag_data["aliases"], implications=tag_data["implications"], - category=tag_data["category"], old_tag=tag_data["old_tag_name"]) + category_id=self.__main.db_connection.get_category_by_name(tag_data["category"])[0]) self.on_tag_search_change() def on_tag_search_item_changed(self, item: QStandardItem):