From e8c0cac4c5c224431caa034790e02bdcd147bec2 Mon Sep 17 00:00:00 2001 From: luxick Date: Fri, 7 Jul 2017 12:46:10 +0200 Subject: [PATCH] Use local database over internet for card searches. --- cardvault/database.py | 107 ++++++++++++++++++++++++++++++++++++++++++ cardvault/search.py | 63 +++++++++++++++---------- cardvault/util.py | 1 + 3 files changed, 145 insertions(+), 26 deletions(-) diff --git a/cardvault/database.py b/cardvault/database.py index 93f283c..b9faa87 100644 --- a/cardvault/database.py +++ b/cardvault/database.py @@ -1,4 +1,5 @@ import sqlite3 +import ast from mtgsdk import Card from cardvault import util @@ -58,6 +59,59 @@ class CardVaultDB: util.log("Database Error", util.LogLevel.Error) util.log(str(err), util.LogLevel.Error) + def search_cards_by_name_filtered(self, term: str, filters: dict, list_size: int) -> dict: + """Search for cards based on the cards name with filter constrains""" + filter_rarity = filters["rarity"] + filer_type = filters["type"] + filter_set = filters["set"] + filter_mana = filters["mana"].split(',') + + sql = 'SELECT * FROM cards WHERE `name` LIKE ?' + parameters = ['%' + term + '%'] + if filter_rarity != "": + sql += ' AND `rarity` = ?' + parameters.append(filter_rarity) + if filer_type != "": + sql += ' AND `types` LIKE ?' + parameters.append(filer_type) + if filter_set != "": + sql += ' AND `set` = ?' + parameters.append(filter_set) + if len(filter_mana) != 0: + for color in filter_mana: + sql += ' AND `manaCost` LIKE ?' + parameters.append('%'+color+'%') + sql += ' LIMIT ?' + parameters.append(list_size) + + con = sqlite3.connect(self.db_file) + cur = con.cursor() + cur.row_factory = sqlite3.Row + cur.execute(sql, parameters) + rows = cur.fetchall() + con.close() + + output = {} + for row in rows: + card = self.table_to_card_mapping(row) + output[card.multiverse_id] = card + return output + + def search_cards_by_name(self, term: str) -> dict: + """Search for cards based on the cards name""" + con = sqlite3.connect(self.db_file) + cur = con.cursor() + cur.row_factory = sqlite3.Row + cur.execute("SELECT * FROM cards WHERE `name` LIKE ? LIMIT 50", ('%'+term+'%', )) + rows = cur.fetchall() + con.close() + + output = {} + for row in rows: + card = self.table_to_card_mapping(row) + output[card.multiverse_id] = card + return output + @staticmethod def card_to_table_mapping(card: Card): """Return the database representation of a card object""" @@ -73,3 +127,56 @@ class CardVaultDB: str(card.original_type), str(card.source), str(card.image_url), str(card.set), str(card.set_name), str(card.id), str(card.legalities), str(card.rulings), str(card.foreign_names)) + + @staticmethod + def table_to_card_mapping(row: sqlite3.Row): + """Return card object representation of a table row""" + card = Card() + card.multiverse_id = row["multiverseid"] + tmp = row["name"] + card.name = tmp + card.layout = row["layout"] + card.mana_cost = row["manacost"] + card.cmc = row["cmc"] + card.colors = row["colors"] + card.type = row["type"] + card.rarity = row["rarity"] + card.text = row["text"] + card.flavor = row["flavor"] + card.artist = row["artist"] + card.number = row["number"] + card.power = row["power"] + card.toughness = row["toughness"] + card.loyalty = row["loyalty"] + card.watermark = row["watermark"] + card.border = row["border"] + card.hand = row["hand"] + card.life = row["life"] + card.release_date = row["releaseDate"] + card.starter = row["starter"] + card.original_text = row["originalText"] + card.original_type = row["originalType"] + card.source = row["source"] + card.image_url = row["imageUrl"] + card.set = row["set"] + card.set_name = row["setName"] + card.id = row["id"] + + # Bool attributes + card.timeshifted = ast.literal_eval(row["timeshifted"]) + + # List attributes + card.names = ast.literal_eval(row["names"]) + card.supertypes = ast.literal_eval(row["supertypes"]) + card.subtypes = ast.literal_eval(row["subtypes"]) + card.types = ast.literal_eval(row["types"]) + card.printings = ast.literal_eval(row["printings"]) + card.variations = ast.literal_eval(row["variations"]) + + # Dict attributes + card.legalities = ast.literal_eval(row["legalities"]) + card.rulings = ast.literal_eval(row["rulings"]) + card.foreign_names = ast.literal_eval(row["foreignNames"]) + + return card + diff --git a/cardvault/search.py b/cardvault/search.py index 6d3ca89..f823b0e 100644 --- a/cardvault/search.py +++ b/cardvault/search.py @@ -205,42 +205,53 @@ class SearchHandlers: return output def search_cards(self, term: str, filters: dict) -> dict: - util.log("Starting online search for '" + term + "'", util.LogLevel.Info) - util.log("Used Filters: " + str(filters), util.LogLevel.Info) - - # Load card info from internet - try: - util.log("Fetching card info ...", util.LogLevel.Info) + """Return a dict of cards based on a search term and filters""" + # Check if a local database can be used for searching + if self.app.config["local_db"]: + util.log("Starting local search for '" + term + "'", util.LogLevel.Info) start = time.time() - cards = Card.where(name=term) \ - .where(colorIdentity=filters["mana"]) \ - .where(types=filters["type"]) \ - .where(set=filters["set"]) \ - .where(rarity=filters["rarity"]) \ - .where(pageSize=50) \ - .where(page=1).all() + + cards = self.app.db.search_cards_by_name_filtered(term, filters, 100) + end = time.time() util.log("Card info fetched in {}s".format(round(end - start, 3)), util.LogLevel.Info) - except (URLError, HTTPError) as err: - util.log(err, util.LogLevel.Error) - return {} + + else: + util.log("Starting online search for '" + term + "'", util.LogLevel.Info) + util.log("Used Filters: " + str(filters), util.LogLevel.Info) + + # Load card info from internet + try: + util.log("Fetching card info ...", util.LogLevel.Info) + start = time.time() + data = Card.where(name=term) \ + .where(colorIdentity=filters["mana"]) \ + .where(types=filters["type"]) \ + .where(set=filters["set"]) \ + .where(rarity=filters["rarity"]) \ + .where(pageSize=50) \ + .where(page=1).all() + end = time.time() + util.log("Card info fetched in {}s".format(round(end - start, 3)), util.LogLevel.Info) + except (URLError, HTTPError) as err: + util.log(err, util.LogLevel.Error) + return {} + + # Remove duplicate entries + if util.SHOW_FROM_ALL_SETS is False: + data = self._remove_duplicates(data) + # Pack results in a dictionary + cards = {} + for card in data: + cards[card.multiverse_id] = card # Check if results were found if len(cards) == 0: # TODO UI show no cards found util.log("No Cards found", util.LogLevel.Info) return {} - util.log("Found " + str(len(cards)) + " cards", util.LogLevel.Info) - # Remove duplicate entries - if util.SHOW_FROM_ALL_SETS is False: - cards = self._remove_duplicates(cards) - - # Pack results in a dictionary - lib = {} - for card in cards: - lib[card.multiverse_id] = card - return lib + return cards # ---------------------------------Search Tree---------------------------------------------- diff --git a/cardvault/util.py b/cardvault/util.py index 24bd226..7c2733e 100644 --- a/cardvault/util.py +++ b/cardvault/util.py @@ -61,6 +61,7 @@ GENERIC_TREE_COLORS ={ default_config = { "hide_duplicates_in_search": False, "start_page": "search", + "local_db": False, "log_level": 3, "legality_colors": { "Banned": "#C65642",