mirror of
https://github.com/correl/mtgsqlive.git
synced 2024-11-21 19:18:41 +00:00
Mark's Changes for SQL (#29)
* Added new fields. - Added `hasLeadershipSkills` and `hasNoDeckLimit` * Update json2sql.py * Changed for new build * Export .sql file * fixes
This commit is contained in:
parent
0d08bb8b92
commit
9b18d52a5d
1 changed files with 291 additions and 241 deletions
|
@ -6,9 +6,11 @@ import json
|
|||
import logging
|
||||
import pathlib
|
||||
import sqlite3
|
||||
import time
|
||||
from typing import Any, Dict, List, Union
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
version = "v4.5.x" # need to automate this
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
@ -24,7 +26,7 @@ def main() -> None:
|
|||
)
|
||||
parser.add_argument(
|
||||
"-o",
|
||||
help="output file (*.sqlite, *.db, *.sqlite3, *.db3)",
|
||||
help="output file (*.sqlite, *.db, *.sqlite3, *.db3, *.sql)",
|
||||
required=True,
|
||||
metavar="fileOut",
|
||||
)
|
||||
|
@ -32,20 +34,37 @@ def main() -> None:
|
|||
|
||||
# Define our I/O paths
|
||||
input_file = pathlib.Path(args.i).expanduser()
|
||||
output_file = pathlib.Path(args.o).expanduser()
|
||||
output_file = {"path": pathlib.Path(args.o).expanduser(), "handle": None}
|
||||
|
||||
if not validate_io_streams(input_file, output_file):
|
||||
exit(1)
|
||||
|
||||
# Build the SQLite database
|
||||
sql_connection = sqlite3.connect(str(output_file))
|
||||
sql_connection.execute("pragma journal_mode=wal;")
|
||||
# Build the SQLite database/file
|
||||
if output_file["path"].suffix == ".sql":
|
||||
output_file["handle"] = open(output_file["path"], "w", encoding="utf8")
|
||||
output_file["handle"].write(
|
||||
"\n".join(
|
||||
(
|
||||
"-- MTGSQLive Output File",
|
||||
"-- ({})".format(str(time.strftime("%Y-%m-%d %H:%M:%S"))),
|
||||
"-- MTGJSON Version: {}".format(version),
|
||||
"",
|
||||
"BEGIN TRANSACTION;",
|
||||
"",
|
||||
"",
|
||||
)
|
||||
)
|
||||
)
|
||||
else:
|
||||
output_file["handle"] = sqlite3.connect(str(output_file["path"]))
|
||||
output_file["handle"].execute("pragma journal_mode=wal;")
|
||||
|
||||
build_sql_schema(sql_connection)
|
||||
parse_and_import_cards(input_file, sql_connection)
|
||||
build_sql_schema(output_file)
|
||||
parse_and_import_cards(input_file, output_file)
|
||||
output_file["handle"].close()
|
||||
|
||||
|
||||
def validate_io_streams(input_file: pathlib.Path, output_file: pathlib.Path) -> bool:
|
||||
def validate_io_streams(input_file: pathlib.Path, output_file: Dict) -> bool:
|
||||
"""
|
||||
Ensure I/O paths are valid and clean for program
|
||||
:param input_file: Input file (JSON)
|
||||
|
@ -61,222 +80,232 @@ def validate_io_streams(input_file: pathlib.Path, output_file: pathlib.Path) ->
|
|||
LOGGER.fatal(f"Invalid input file/directory. ({input_file})")
|
||||
return False
|
||||
|
||||
output_file.parent.mkdir(exist_ok=True)
|
||||
if output_file.is_file():
|
||||
LOGGER.warning(f"Output file {output_file} exists already, moving it.")
|
||||
output_file.replace(output_file.parent.joinpath(output_file.name + ".old"))
|
||||
output_file["path"].parent.mkdir(exist_ok=True)
|
||||
if output_file["path"].is_file():
|
||||
LOGGER.warning(f"Output file {output_file['path']} exists already, moving it.")
|
||||
output_file["path"].replace(
|
||||
output_file["path"].parent.joinpath(output_file["path"].name + ".old")
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def build_sql_schema(sql_connection: sqlite3.Connection) -> None:
|
||||
def build_sql_schema(output_file: Dict) -> None:
|
||||
"""
|
||||
Create the SQLite DB schema
|
||||
:param sql_connection: Connection to the database
|
||||
:param output_file: Output info dict
|
||||
"""
|
||||
LOGGER.info("Building SQLite Schema")
|
||||
cursor = sql_connection.cursor()
|
||||
|
||||
# Build Set table
|
||||
cursor.execute(
|
||||
"CREATE TABLE `sets` ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||
"baseSetSize INTEGER,"
|
||||
"block TEXT,"
|
||||
"boosterV3 TEXT,"
|
||||
"code TEXT UNIQUE NOT NULL,"
|
||||
"codeV3 TEXT,"
|
||||
"isFoilOnly INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isForeignOnly INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isOnlineOnly INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isPartialPreview INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"keyruneCode TEXT,"
|
||||
"mcmId INTEGER,"
|
||||
"mcmName TEXT,"
|
||||
"meta TEXT,"
|
||||
"mtgoCode TEXT,"
|
||||
"name TEXT,"
|
||||
"parentCode TEXT,"
|
||||
"releaseDate TEXT,"
|
||||
"tcgplayerGroupId INTEGER,"
|
||||
"totalSetSize INTEGER,"
|
||||
"type TEXT"
|
||||
")"
|
||||
)
|
||||
|
||||
# Build cards table
|
||||
cursor.execute(
|
||||
"CREATE TABLE `cards` ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||
"artist TEXT,"
|
||||
"borderColor TEXT,"
|
||||
"colorIdentity TEXT,"
|
||||
"colorIndicator TEXT,"
|
||||
"colors TEXT,"
|
||||
"convertedManaCost FLOAT,"
|
||||
"duelDeck TEXT(1),"
|
||||
"edhrecRank TEXT,"
|
||||
"faceConvertedManaCost FLOAT,"
|
||||
"flavorText TEXT,"
|
||||
"frameEffect TEXT,"
|
||||
"frameVersion TEXT,"
|
||||
"hand TEXT,"
|
||||
"hasFoil INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"hasNoDeckLimit INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"hasNonFoil INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isAlternative INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isArena INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isFullArt INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isMtgo INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isOnlineOnly INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isOversized INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isPaper INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isPromo INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isReprint INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isReserved INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isStarter INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isStorySpotlight INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isTextless INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"isTimeshifted INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"layout TEXT,"
|
||||
"leadershipSkills TEXT,"
|
||||
"life TEXT,"
|
||||
"loyalty TEXT,"
|
||||
"manaCost TEXT,"
|
||||
"mcmId INTEGER,"
|
||||
"mcmMetaId INTEGER,"
|
||||
"mcmName TEXT,"
|
||||
"mtgArenaId INTEGER,"
|
||||
"mtgoFoilId INTEGER,"
|
||||
"mtgoId INTEGER,"
|
||||
"mtgstocksId INTEGER,"
|
||||
"multiverseId INTEGER,"
|
||||
"name TEXT,"
|
||||
"names TEXT,"
|
||||
"number TEXT,"
|
||||
"originalText TEXT,"
|
||||
"originalType TEXT,"
|
||||
"power TEXT,"
|
||||
"printings TEXT,"
|
||||
"purchaseUrls TEXT,"
|
||||
"rarity TEXT,"
|
||||
"scryfallId TEXT(36),"
|
||||
"scryfallIllustrationId TEXT(36),"
|
||||
"scryfallOracleId TEXT(36),"
|
||||
"setCode TEXT REFERENCES sets(code) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||
"side TEXT,"
|
||||
"subtypes TEXT,"
|
||||
"supertypes TEXT,"
|
||||
"tcgplayerProductId INTEGER,"
|
||||
"tcgplayerPurchaseUrl TEXT,"
|
||||
"text TEXT,"
|
||||
"toughness TEXT,"
|
||||
"type TEXT,"
|
||||
"types TEXT,"
|
||||
"uuid TEXT(36) UNIQUE NOT NULL,"
|
||||
"variations TEXT,"
|
||||
"watermark TEXT"
|
||||
")"
|
||||
#"CREATE UNIQUE INDEX 'cards_uuid' ON cards(uuid);"
|
||||
)
|
||||
|
||||
# Build tokens table
|
||||
cursor.execute(
|
||||
"CREATE TABLE `tokens` ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||
"artist TEXT,"
|
||||
"borderColor TEXT,"
|
||||
"colorIdentity TEXT,"
|
||||
"colorIndicator TEXT,"
|
||||
"colors TEXT,"
|
||||
"duelDeck TEXT(1),"
|
||||
"isOnlineOnly INTEGER NOT NULL DEFAULT 0," # boolean
|
||||
"layout TEXT,"
|
||||
"loyalty TEXT,"
|
||||
"name TEXT,"
|
||||
"names TEXT,"
|
||||
"number TEXT,"
|
||||
"power TEXT,"
|
||||
"reverseRelated TEXT,"
|
||||
"scryfallId TEXT(36),"
|
||||
"scryfallIllustrationId TEXT(36),"
|
||||
"scryfallOracleId TEXT(36),"
|
||||
"setCode TEXT REFERENCES sets(code) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||
"side TEXT,"
|
||||
"text TEXT,"
|
||||
"toughness TEXT,"
|
||||
"type TEXT,"
|
||||
"uuid TEXT(36) UNIQUE,"
|
||||
"watermark TEXT"
|
||||
")"
|
||||
)
|
||||
|
||||
# Translations for set names
|
||||
cursor.execute(
|
||||
"CREATE TABLE `set_translations` ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||
"language TEXT,"
|
||||
"setCode TEXT REFERENCES sets(code) ON UPDATE CASCADE ON DELETE CASCADE,"
|
||||
"translation TEXT"
|
||||
")"
|
||||
)
|
||||
|
||||
# Build foreignData table
|
||||
cursor.execute(
|
||||
"CREATE TABLE `foreignData` ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||
"flavorText TEXT,"
|
||||
"language TEXT,"
|
||||
"multiverseId INTEGER,"
|
||||
"name TEXT,"
|
||||
"text TEXT,"
|
||||
"type TEXT,"
|
||||
"uuid TEXT(36) REFERENCES cards(uuid) ON UPDATE CASCADE ON DELETE CASCADE"
|
||||
")"
|
||||
)
|
||||
|
||||
# Build legalities table
|
||||
cursor.execute(
|
||||
"CREATE TABLE `legalities` ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||
"format TEXT,"
|
||||
"status TEXT,"
|
||||
"uuid TEXT(36) REFERENCES cards(uuid) ON UPDATE CASCADE ON DELETE CASCADE"
|
||||
")"
|
||||
)
|
||||
|
||||
# Build ruling table
|
||||
cursor.execute(
|
||||
"CREATE TABLE `rulings` ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||
"date TEXT,"
|
||||
"text TEXT,"
|
||||
"uuid TEXT(36) REFERENCES cards(uuid) ON UPDATE CASCADE ON DELETE CASCADE"
|
||||
")"
|
||||
)
|
||||
|
||||
# Build prices table
|
||||
cursor.execute(
|
||||
"CREATE TABLE `prices` ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||
"date TEXT,"
|
||||
"price REAL,"
|
||||
"type TEXT,"
|
||||
"uuid TEXT(36) REFERENCES cards(uuid) ON UPDATE CASCADE ON DELETE CASCADE"
|
||||
")"
|
||||
)
|
||||
schema = {
|
||||
"sets": [
|
||||
"CREATE TABLE `sets` (",
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,",
|
||||
"baseSetSize INTEGER,",
|
||||
"block TEXT,",
|
||||
"boosterV3 TEXT,",
|
||||
"code TEXT UNIQUE NOT NULL,",
|
||||
"codeV3 TEXT,",
|
||||
"isFoilOnly INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isForeignOnly INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isOnlineOnly INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isPartialPreview INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"keyruneCode TEXT,",
|
||||
"mcmId INTEGER,",
|
||||
"mcmName TEXT,",
|
||||
"meta TEXT,",
|
||||
"mtgoCode TEXT,",
|
||||
"name TEXT,",
|
||||
"parentCode TEXT,",
|
||||
"releaseDate TEXT,",
|
||||
"tcgplayerGroupId INTEGER,",
|
||||
"totalSetSize INTEGER,",
|
||||
"type TEXT",
|
||||
");",
|
||||
"",
|
||||
"",
|
||||
],
|
||||
"cards": [
|
||||
"CREATE TABLE `cards` (",
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,",
|
||||
"artist TEXT,",
|
||||
"borderColor TEXT,",
|
||||
"colorIdentity TEXT,",
|
||||
"colorIndicator TEXT,",
|
||||
"colors TEXT,",
|
||||
"convertedManaCost FLOAT,",
|
||||
"duelDeck TEXT(1),",
|
||||
"edhrecRank TEXT,",
|
||||
"faceConvertedManaCost FLOAT,",
|
||||
"flavorText TEXT,",
|
||||
"frameEffect TEXT,",
|
||||
"frameVersion TEXT,",
|
||||
"hand TEXT,",
|
||||
"hasFoil INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"hasNoDeckLimit INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"hasNonFoil INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isAlternative INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isArena INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isFullArt INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isMtgo INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isOnlineOnly INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isOversized INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isPaper INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isPromo INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isReprint INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isReserved INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isStarter INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isStorySpotlight INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isTextless INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"isTimeshifted INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"layout TEXT,",
|
||||
"leadershipSkills TEXT,",
|
||||
"life TEXT,",
|
||||
"loyalty TEXT,",
|
||||
"manaCost TEXT,",
|
||||
"mcmId INTEGER,",
|
||||
"mcmMetaId INTEGER,",
|
||||
"mcmName TEXT,",
|
||||
"mtgArenaId INTEGER,",
|
||||
"mtgoFoilId INTEGER,",
|
||||
"mtgoId INTEGER,",
|
||||
"mtgstocksId INTEGER,",
|
||||
"multiverseId INTEGER,",
|
||||
"name TEXT,",
|
||||
"names TEXT,",
|
||||
"number TEXT,",
|
||||
"originalText TEXT,",
|
||||
"originalType TEXT,",
|
||||
"power TEXT,",
|
||||
"printings TEXT,",
|
||||
"purchaseUrls TEXT,",
|
||||
"rarity TEXT,",
|
||||
"scryfallId TEXT(36),",
|
||||
"scryfallIllustrationId TEXT(36),",
|
||||
"scryfallOracleId TEXT(36),",
|
||||
"setCode TEXT REFERENCES sets(code) ON UPDATE CASCADE ON DELETE CASCADE,",
|
||||
"side TEXT,",
|
||||
"subtypes TEXT,",
|
||||
"supertypes TEXT,",
|
||||
"tcgplayerProductId INTEGER,",
|
||||
"tcgplayerPurchaseUrl TEXT,",
|
||||
"text TEXT,",
|
||||
"toughness TEXT,",
|
||||
"type TEXT,",
|
||||
"types TEXT,",
|
||||
"uuid TEXT(36) UNIQUE NOT NULL,",
|
||||
"variations TEXT,",
|
||||
"watermark TEXT",
|
||||
");",
|
||||
# "CREATE UNIQUE INDEX 'cards_uuid' ON cards(uuid);"
|
||||
"",
|
||||
"",
|
||||
],
|
||||
"tokens": [
|
||||
"CREATE TABLE `tokens` (",
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,",
|
||||
"artist TEXT,",
|
||||
"borderColor TEXT,",
|
||||
"colorIdentity TEXT,",
|
||||
"colorIndicator TEXT,",
|
||||
"colors TEXT,",
|
||||
"duelDeck TEXT(1),",
|
||||
"isOnlineOnly INTEGER NOT NULL DEFAULT 0,", # boolean
|
||||
"layout TEXT,",
|
||||
"loyalty TEXT,",
|
||||
"name TEXT,",
|
||||
"names TEXT,",
|
||||
"number TEXT,",
|
||||
"power TEXT,",
|
||||
"reverseRelated TEXT,",
|
||||
"scryfallId TEXT(36),",
|
||||
"scryfallIllustrationId TEXT(36),",
|
||||
"scryfallOracleId TEXT(36),",
|
||||
"setCode TEXT REFERENCES sets(code) ON UPDATE CASCADE ON DELETE CASCADE,",
|
||||
"side TEXT,",
|
||||
"text TEXT,",
|
||||
"toughness TEXT,",
|
||||
"type TEXT,",
|
||||
"uuid TEXT(36) UNIQUE,",
|
||||
"watermark TEXT",
|
||||
");",
|
||||
"",
|
||||
"",
|
||||
],
|
||||
"set_translations": [
|
||||
"CREATE TABLE `set_translations` (",
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,",
|
||||
"language TEXT,",
|
||||
"setCode TEXT REFERENCES sets(code) ON UPDATE CASCADE ON DELETE CASCADE,",
|
||||
"translation TEXT",
|
||||
");",
|
||||
"",
|
||||
"",
|
||||
],
|
||||
"foreignData": [
|
||||
"CREATE TABLE `foreignData` (",
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,",
|
||||
"flavorText TEXT,",
|
||||
"language TEXT,",
|
||||
"multiverseId INTEGER,",
|
||||
"name TEXT,",
|
||||
"text TEXT,",
|
||||
"type TEXT,",
|
||||
"uuid TEXT(36) REFERENCES cards(uuid) ON UPDATE CASCADE ON DELETE CASCADE",
|
||||
");",
|
||||
"",
|
||||
"",
|
||||
],
|
||||
"legalities": [
|
||||
"CREATE TABLE `legalities` (",
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,",
|
||||
"format TEXT,",
|
||||
"status TEXT,",
|
||||
"uuid TEXT(36) REFERENCES cards(uuid) ON UPDATE CASCADE ON DELETE CASCADE",
|
||||
");",
|
||||
"",
|
||||
"",
|
||||
],
|
||||
"rulings": [
|
||||
"CREATE TABLE `rulings` (",
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,",
|
||||
"date TEXT,",
|
||||
"text TEXT,",
|
||||
"uuid TEXT(36) REFERENCES cards(uuid) ON UPDATE CASCADE ON DELETE CASCADE",
|
||||
");",
|
||||
"",
|
||||
"",
|
||||
],
|
||||
"prices": [
|
||||
"CREATE TABLE `prices` (",
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,",
|
||||
"date TEXT,",
|
||||
"price REAL,",
|
||||
"type TEXT,",
|
||||
"uuid TEXT(36) REFERENCES cards(uuid) ON UPDATE CASCADE ON DELETE CASCADE",
|
||||
");",
|
||||
"",
|
||||
"",
|
||||
],
|
||||
}
|
||||
|
||||
# Execute the commands
|
||||
sql_connection.commit()
|
||||
if output_file["path"].suffix == ".sql":
|
||||
for q in schema.values():
|
||||
output_file["handle"].write("\n".join(q))
|
||||
output_file["handle"].write("COMMIT;\n\nBEGIN TRANSACTION;\n")
|
||||
else:
|
||||
cursor = output_file["handle"].cursor()
|
||||
for q in schema.values():
|
||||
cursor.execute("".join(q))
|
||||
output_file["handle"].commit()
|
||||
|
||||
|
||||
def parse_and_import_cards(
|
||||
input_file: pathlib.Path, sql_connection: sqlite3.Connection
|
||||
) -> None:
|
||||
def parse_and_import_cards(input_file: pathlib.Path, output_file: Dict) -> None:
|
||||
"""
|
||||
Parse the JSON cards and input them into the database
|
||||
:param input_file: AllSets.json file
|
||||
:param sql_connection: Database connection
|
||||
:param output_file: Uutput info dictionary
|
||||
"""
|
||||
if input_file.is_file():
|
||||
LOGGER.info("Loading JSON into memory")
|
||||
|
@ -287,26 +316,24 @@ def parse_and_import_cards(
|
|||
# Handle set insertion
|
||||
LOGGER.info("Inserting set row for {}".format(set_code))
|
||||
set_insert_values = handle_set_row_insertion(set_data)
|
||||
sql_dict_insert(set_insert_values, "sets", sql_connection)
|
||||
sql_dict_insert(set_insert_values, "sets", output_file)
|
||||
|
||||
for card in set_data.get("cards"):
|
||||
LOGGER.debug("Inserting card row for {}".format(card.get("name")))
|
||||
card_attr: Dict[str, Any] = handle_card_row_insertion(card, set_code)
|
||||
sql_insert_all_card_fields(card_attr, sql_connection)
|
||||
sql_insert_all_card_fields(card_attr, output_file)
|
||||
|
||||
for token in set_data.get("tokens"):
|
||||
LOGGER.debug("Inserting token row for {}".format(token.get("name")))
|
||||
token_attr = handle_token_row_insertion(token, set_code)
|
||||
sql_dict_insert(token_attr, "tokens", sql_connection)
|
||||
sql_dict_insert(token_attr, "tokens", output_file)
|
||||
|
||||
for language, translation in set_data.get("translations", {}).items():
|
||||
LOGGER.debug("Inserting set_translation row for {}".format(language))
|
||||
set_translation_attr = handle_set_translation_row_insertion(
|
||||
language, translation, set_code
|
||||
)
|
||||
sql_dict_insert(
|
||||
set_translation_attr, "set_translations", sql_connection
|
||||
)
|
||||
sql_dict_insert(set_translation_attr, "set_translations", output_file)
|
||||
elif input_file.is_dir():
|
||||
for setFile in input_file.glob("*.json"):
|
||||
LOGGER.info("Loading {} into memory...".format(setFile.name))
|
||||
|
@ -314,50 +341,53 @@ def parse_and_import_cards(
|
|||
set_code = setFile.stem
|
||||
LOGGER.info("Building set: {}".format(set_code))
|
||||
set_insert_values = handle_set_row_insertion(set_data)
|
||||
sql_dict_insert(set_insert_values, "sets", sql_connection)
|
||||
sql_dict_insert(set_insert_values, "sets", output_file)
|
||||
|
||||
for card in set_data.get("cards"):
|
||||
LOGGER.debug("Inserting card row for {}".format(card.get("name")))
|
||||
card_attr: Dict[str, Any] = handle_card_row_insertion(card, set_code)
|
||||
sql_insert_all_card_fields(card_attr, sql_connection)
|
||||
sql_insert_all_card_fields(card_attr, output_file)
|
||||
|
||||
for token in set_data.get("tokens"):
|
||||
LOGGER.debug("Inserting token row for {}".format(token.get("name")))
|
||||
token_attr = handle_token_row_insertion(token, set_code)
|
||||
sql_dict_insert(token_attr, "tokens", sql_connection)
|
||||
sql_dict_insert(token_attr, "tokens", output_file)
|
||||
|
||||
for language, translation in set_data.get("translations", {}).items():
|
||||
LOGGER.debug("Inserting set_translation row for {}".format(language))
|
||||
set_translation_attr = handle_set_translation_row_insertion(
|
||||
language, translation, set_code
|
||||
)
|
||||
sql_dict_insert(
|
||||
set_translation_attr, "set_translations", sql_connection
|
||||
)
|
||||
sql_connection.commit()
|
||||
sql_dict_insert(set_translation_attr, "set_translations", output_file)
|
||||
|
||||
if output_file["path"].suffix == ".sql":
|
||||
output_file["handle"].write("COMMIT;")
|
||||
else:
|
||||
output_file["handle"].commit()
|
||||
|
||||
|
||||
def sql_insert_all_card_fields(
|
||||
card_attributes: Dict[str, Any], sql_connection: sqlite3.Connection
|
||||
card_attributes: Dict[str, Any], output_file: Dict
|
||||
) -> None:
|
||||
"""
|
||||
Given all of the card's data, insert the data into the
|
||||
appropriate SQLite tables.
|
||||
:param card_attributes: Tuple of data
|
||||
:param sql_connection: DB Connection
|
||||
:param output_file: Output info dictionary
|
||||
"""
|
||||
sql_dict_insert(card_attributes["cards"], "cards", sql_connection)
|
||||
sql_dict_insert(card_attributes["cards"], "cards", output_file)
|
||||
|
||||
for foreign_val in card_attributes["foreignData"]:
|
||||
sql_dict_insert(foreign_val, "foreignData", sql_connection)
|
||||
sql_dict_insert(foreign_val, "foreignData", output_file)
|
||||
|
||||
for legal_val in card_attributes["legalities"]:
|
||||
sql_dict_insert(legal_val, "legalities", sql_connection)
|
||||
sql_dict_insert(legal_val, "legalities", output_file)
|
||||
|
||||
for rule_val in card_attributes["rulings"]:
|
||||
sql_dict_insert(rule_val, "rulings", sql_connection)
|
||||
sql_dict_insert(rule_val, "rulings", output_file)
|
||||
|
||||
for price_val in card_attributes["prices"]:
|
||||
sql_dict_insert(price_val, "prices", sql_connection)
|
||||
sql_dict_insert(price_val, "prices", output_file)
|
||||
|
||||
|
||||
def handle_set_row_insertion(set_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
|
@ -463,10 +493,10 @@ def handle_price_rows(
|
|||
:return: List of dicts, ready for insertion
|
||||
"""
|
||||
prices = []
|
||||
for type in card_data["prices"]:
|
||||
for date, price in card_data["prices"][type].items():
|
||||
for price_type in card_data["prices"]:
|
||||
for date, price in card_data["prices"][price_type].items():
|
||||
prices.append(
|
||||
{"uuid": card_uuid, "type": type, "price": price, "date": date}
|
||||
{"uuid": card_uuid, "type": price_type, "price": price, "date": date}
|
||||
)
|
||||
|
||||
return prices
|
||||
|
@ -553,7 +583,7 @@ def handle_card_row_insertion(
|
|||
}
|
||||
|
||||
|
||||
def modify_for_sql_insert(data: Any) -> Union[str, int, float]:
|
||||
def modify_for_sql_insert(data: Any) -> Union[str, int, float, None]:
|
||||
"""
|
||||
Arrays and booleans can't be inserted, so we need to stringify
|
||||
:param data: Data to modify
|
||||
|
@ -578,17 +608,37 @@ def modify_for_sql_insert(data: Any) -> Union[str, int, float]:
|
|||
return ""
|
||||
|
||||
|
||||
def sql_dict_insert(
|
||||
data: Dict[str, Any], table: str, sql_connection: sqlite3.Connection
|
||||
) -> None:
|
||||
def sql_dict_insert(data: Dict[str, Any], table: str, output_file: Dict) -> None:
|
||||
"""
|
||||
Insert a dictionary into a sqlite table
|
||||
:param data: Dict to insert
|
||||
:param table: Table to insert to
|
||||
:param sql_connection: SQL connection
|
||||
:param output_file: Output info dictionary
|
||||
"""
|
||||
cursor = sql_connection.cursor()
|
||||
columns = ", ".join(data.keys())
|
||||
placeholders = ":" + ", :".join(data.keys())
|
||||
query = f"INSERT INTO {table} ({columns}) VALUES ({placeholders})"
|
||||
cursor.execute(query, data)
|
||||
if output_file["path"].suffix == ".sql":
|
||||
for key in data.keys():
|
||||
if isinstance(data[key], str):
|
||||
data[key] = "'" + data[key].replace("'", "''").replace('"', '""') + "'"
|
||||
if str(data[key]) == "False":
|
||||
data[key] = 0
|
||||
if str(data[key]) == "True":
|
||||
data[key] = 1
|
||||
if data[key] is None:
|
||||
data[key] = "NULL"
|
||||
query = (
|
||||
"INSERT INTO "
|
||||
+ table
|
||||
+ " ("
|
||||
+ ", ".join(data.keys())
|
||||
+ ") VALUES ({"
|
||||
+ "}, {".join(data.keys())
|
||||
+ "});\n"
|
||||
)
|
||||
query = query.format(**data)
|
||||
output_file["handle"].write(query)
|
||||
else:
|
||||
cursor = output_file["handle"].cursor()
|
||||
columns = ", ".join(data.keys())
|
||||
placeholders = ":" + ", :".join(data.keys())
|
||||
query = f"INSERT INTO {table} ({columns}) VALUES ({placeholders})"
|
||||
cursor.execute(query, data)
|
||||
|
|
Loading…
Reference in a new issue