From 82120d985d5a23a6f09c5c1bf5373c68ec7f95a5 Mon Sep 17 00:00:00 2001 From: Pablo Minue Date: Sun, 7 Jul 2024 19:02:55 +0200 Subject: [PATCH] Worked on dialects for the insert query, tested on sqlite3, added columns to fetch method on query --- .gitignore | 5 +- dist/pysqltools-0.2.6-py3-none-any.whl | Bin 0 -> 12954 bytes dist/pysqltools-0.2.6.tar.gz | Bin 0 -> 10433 bytes pyproject.toml | 2 +- pysqltools/src/connection/connection.py | 8 +- pysqltools/src/sql/constants.py | 1 + pysqltools/src/sql/insert.py | 218 ++++++++++++++++++------ pysqltools/src/sql/table.py | 18 +- "pysqltools/\302\241" | 0 tests/test_connections.py | 54 +++++- tests/test_queries.py | 4 +- 11 files changed, 244 insertions(+), 66 deletions(-) create mode 100644 dist/pysqltools-0.2.6-py3-none-any.whl create mode 100644 dist/pysqltools-0.2.6.tar.gz delete mode 100644 "pysqltools/\302\241" diff --git a/.gitignore b/.gitignore index 5985055..df6e1a2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.pytest_cache __pycache__ -.pyc -testings.py \ No newline at end of file +*.pyc +testings.py +*.sqlite3 diff --git a/dist/pysqltools-0.2.6-py3-none-any.whl b/dist/pysqltools-0.2.6-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..dc6fb7badce23b8f4eb53643292b4b1438af7b9a GIT binary patch literal 12954 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 None: self.conn.commit() except: lg.log.warning("Connection can not be commited") - except: - raise ConnectionException + except Exception as e: + raise ConnectionException(e) def fetch(self, sql: Query, dataframe: bool = False): """ @@ -84,7 +84,11 @@ def fetch(self, sql: Query, dataframe: bool = False): else: cursor = self.conn.cursor() cursor.execute(sql.sql) + if hasattr(cursor, "description"): + columns = [i[0] for i in cursor.description] if hasattr(cursor, "fetchall"): + if dataframe: + return pd.DataFrame(cursor.fetchall(), columns=columns) return cursor.fetchall() else: rows = [] diff --git a/pysqltools/src/sql/constants.py b/pysqltools/src/sql/constants.py index 7e5409d..807f1c4 100644 --- a/pysqltools/src/sql/constants.py +++ b/pysqltools/src/sql/constants.py @@ -10,4 +10,5 @@ "float64": "double", "bool": "bool", "datetime64": "timestamp", + "datetime64[ns]": "timestamp", } diff --git a/pysqltools/src/sql/insert.py b/pysqltools/src/sql/insert.py index 1d3dc95..e58126c 100644 --- a/pysqltools/src/sql/insert.py +++ b/pysqltools/src/sql/insert.py @@ -12,59 +12,159 @@ lg = PabLog("Insert") -def prepare_value(val: Any) -> Any: +def prepare_value(val: Any, dialect: str) -> Any: """ Format value from Python types to SQL Types """ - if isinstance(val, bool): + if dialect.lower().__contains__("trino"): + if isinstance(val, str): + return f"'{val}'" + if isinstance(val, bool): + return val + if isinstance(val, dict): + val = str(val).replace("'", '"') + if isinstance(val, pd.Timestamp): + val = "TIMESTAMP '" + str(val) + "'" + if isinstance(val, date): + val = "DATE '" + str(val) + "'" + if isinstance(val, list): + val = "ARRAY " + str(val) + if isinstance(val, float): + val = "DOUBLE '" + str(val) + "'" + if isinstance(val, int): + val = "INT '" + str(val) + "'" + if pd.isnull(val): + val = "NULL" + + try: + if ( + "'" in val + and "DOUBLE" not in val + and "INT" not in val + and "TIMESTAMP" not in val + and "DATE" not in val + ): + val = val.replace("'", "''") + except TypeError: + lg.log.warning("Not Adding Quotes") + return val - if isinstance(val, dict): - val = str(val).replace("'", '"') - if isinstance(val, pd.Timestamp): - val = "TIMESTAMP '" + str(val) + "'" - if isinstance(val, date): - val = "DATE '" + str(val) + "'" - if isinstance(val, list): - val = "ARRAY " + str(val) - if isinstance(val, float): - val = "DOUBLE '" + str(val) + "'" - if isinstance(val, int): - val = "INT '" + str(val) + "'" - if pd.isnull(val): - val = "NULL" - - try: - if ( - "'" in val - and "DOUBLE" not in val - and "INT" not in val - and "TIMESTAMP" not in val - and "DATE" not in val - ): - val = val.replace("'", "''") - except TypeError: - lg.log.warning("Not Adding Quotes") + if dialect.lower().__contains__("mysql"): + if isinstance(val, str): + return f"'{val}'" + if isinstance(val, bool): + return bool(val) + if isinstance(val, dict): + val = str(val).replace("'", '"') + if isinstance(val, pd.Timestamp): + val = f"'{val}'" + if isinstance(val, date): + val = f"'{val}'" + if isinstance(val, list): + val = f"'{str(val)}'" + if isinstance(val, float): + val = str(val) + if isinstance(val, int): + val = str(val) + if pd.isnull(val): + val = "NULL" + + return val + + if dialect.lower().__contains__("sqlite"): + if isinstance(val, str): + return f"'{val}'" + if isinstance(val, bool): + return bool(val) + if isinstance(val, dict): + val = str(val).replace("'", '"') + if isinstance(val, pd.Timestamp): + val = f"'{val}'" + if isinstance(val, date): + val = f"'{val}'" + if isinstance(val, list): + val = f"'{str(val)}'" + if isinstance(val, float): + val = str(val) + if isinstance(val, int): + val = str(val) + if pd.isnull(val): + val = "NULL" - return val + return val + if dialect.lower().__contains__("ibm"): + if isinstance(val, str): + return f"'{val}'" + if isinstance(val, bool): + return bool(val) + if isinstance(val, dict): + val = str(val).replace("'", '"') + if isinstance(val, pd.Timestamp): + val = f"TIMESTAMP '{val}'" + if isinstance(val, date): + val = f"DATE '{val}'" + if isinstance(val, list): + val = f"'{str(val)}'" + if isinstance(val, float): + val = str(val) + if isinstance(val, int): + val = str(val) + if pd.isnull(val): + val = "NULL" -def join_values(data: list[Any]) -> str: + return val + + if dialect.lower().__contains__("sqlserver"): + if isinstance(val, str): + return f"'{val}'" + if isinstance(val, bool): + return bool(val) + if isinstance(val, dict): + val = str(val).replace("'", '"') + if isinstance(val, pd.Timestamp): + val = f"'{val}'" + if isinstance(val, date): + val = f"'{val}'" + if isinstance(val, list): + val = f"'{str(val)}'" + if isinstance(val, float): + val = str(val) + if isinstance(val, int): + val = str(val) + if pd.isnull(val): + val = "NULL" + + return val + + if dialect.lower().__contains__("mariadb"): + if isinstance(val, str): + return f"'{val}'" + if isinstance(val, bool): + return bool(val) + if isinstance(val, dict): + val = str(val).replace("'", '"') + if isinstance(val, pd.Timestamp): + val = f"'{val}'" + if isinstance(val, date): + val = f"'{val}'" + if isinstance(val, list): + val = f"'{str(val)}'" + if isinstance(val, float): + val = str(val) + if isinstance(val, int): + val = str(val) + if pd.isnull(val): + val = "NULL" + return val + + +def join_values(data: list[Any], dialect: str) -> str: """ Create a String for the VALUES () SQL Syntax """ clean_list = [] for val in data: - if isinstance(val, bool): - val = str(val) - if ( - isinstance(val, str) - and "DOUBLE" not in val - and "INT" not in val - and "TIMESTAMP" not in val - and "DATE" not in val - and "ARRAY" not in val - ) and val.lower() not in ["true", "false"]: - val = "'" + val + "'" try: if "NULL" in val: val = "NULL" @@ -76,18 +176,22 @@ def join_values(data: list[Any]) -> str: return "(" + str_data + ")" -def pandas_to_sql(df: pd.DataFrame) -> Generator[str, None, None]: +def pandas_to_sql(df: pd.DataFrame, dialect: str) -> Generator[str, None, None]: """ Generator to get one row insert statement """ for row in df.values: - data_list = [prepare_value(x) for x in row] - data_string = join_values(data_list) + data_list = [prepare_value(x, dialect=dialect) for x in row] + data_string = join_values(data_list, dialect=dialect) yield data_string def generate_insert_query( - df: pd.DataFrame, table: str = None, schema: str = None, batch_size: int = 5000 + df: pd.DataFrame, + table: str = None, + schema: str = None, + batch_size: int = 5000, + dialect: str = "trino", ) -> Generator[Query, None, None]: if df.empty: raise TypeError("DataFrame can not be empty") @@ -96,7 +200,7 @@ def generate_insert_query( percentage = round(100 * previous_iter / len(df), 2) lg.log.info("Generating Insert Queries... %s", percentage) batch = df.iloc[previous_iter : previous_iter + batch_size] - data_points = list(pandas_to_sql(batch)) + data_points = list(pandas_to_sql(batch, dialect)) data_points_string = ",".join(data_points) if schema and table: table = f"{schema}.{table}" @@ -111,21 +215,29 @@ def generate_insert_query( def insert_pandas( df: pd.DataFrame, connection: SQLConnection, - table: str, - schema: str, batch_size: int, + table: str, + schema: str = "", + dialect: str = "trino", ): if not table and schema: raise TypeError("Table and Schema need to be provided") with Progress() as progress: iterations = len(df) / batch_size - task1 = progress.add_task("[red]Generating Queries...", total=1000) - task2 = progress.add_task("[green]Inserting Data...", total=iterations) - task3 = progress.add_task("[cyan]Finishing...", total=1000) + task1 = progress.add_task("[red] Generating Queries...", total=1000) + task2 = progress.add_task("[green] Inserting Data...", total=iterations) + task3 = progress.add_task("[cyan] Finishing...", total=1000) for _ in range(1000): progress.update(task1, advance=1.0) - for query in generate_insert_query(df, table, schema, batch_size): - connection.execute(query) + for query in generate_insert_query( + df, table, schema, batch_size, dialect=dialect + ): + try: + connection.execute(query) + except Exception as e: + lg.log.warning("Query Execution Failed") + lg.log.error(e) + print(query.sql) progress.update(task2, advance=1) for i in range(1000): progress.update(task3, advance=1.0) diff --git a/pysqltools/src/sql/table.py b/pysqltools/src/sql/table.py index 21c1386..0c7cefc 100644 --- a/pysqltools/src/sql/table.py +++ b/pysqltools/src/sql/table.py @@ -7,6 +7,8 @@ import pandas as pd import sqlparse +from pysqltools.src.sql.query import Query + from .constants import TYPE_MAPPING from .insert import insert_pandas @@ -22,7 +24,11 @@ def __init__(self, table: str, schema: Union[str, None] = None) -> None: self.table = f"{schema}.{table}" def create_from_df( - self, df: pd.DataFrame, insert_data: bool = False, **insert_kwargs: Any + self, + df: pd.DataFrame, + execute: bool = False, + insert_data: bool = False, + **insert_kwargs: Any, ) -> str: """ Get the SQL statement to create a SQL table based on a Pandas DataFrame. If the insert_data argument is set to True, @@ -41,12 +47,14 @@ def create_from_df( ), ) ) - sql = f"CREATE TABLE {self.table} ( " + sql = f"CREATE TABLE IF NOT EXISTS {self.table} ( " for k, v in columns.items(): sql += f"{k} {v}, " sql = sql[:-2] + " )" if not insert_data: return sqlparse.format(sql, encoding="utf-8") + if execute: + insert_kwargs["connection"].execute(Query(sql)) if "batch_size" in insert_kwargs: batch_size = insert_kwargs["batch_size"] else: @@ -57,8 +65,10 @@ def create_from_df( connection=insert_kwargs["connection"], table=self.table, batch_size=batch_size, + dialect=insert_kwargs["dialect"], ) - except TypeError: + except TypeError as e: raise TypeError( - "Please include the insert arguments into the create_table_from_df method" + "Please include the insert arguments into the create_table_from_df method", + e, ) diff --git "a/pysqltools/\302\241" "b/pysqltools/\302\241" deleted file mode 100644 index e69de29..0000000 diff --git a/tests/test_connections.py b/tests/test_connections.py index 3d06263..cf21670 100644 --- a/tests/test_connections.py +++ b/tests/test_connections.py @@ -1,3 +1,4 @@ +import sqlite3 from datetime import datetime from unittest.mock import MagicMock, patch @@ -5,9 +6,12 @@ import mysql.connector import mysql.connector.cursor import pandas as pd +import pytest from pysqltools.src.connection.connection import SQLConnection from pysqltools.src.sql.insert import insert_pandas +from pysqltools.src.sql.query import Query +from pysqltools.src.sql.table import Table df = pd.DataFrame( { @@ -31,8 +35,56 @@ def test_insert_with_conn(mock_connect, mock_cursor, mock_commit, mock_execute): conn = SQLConnection(conn=mock_conn) conn.conn.cursor = MagicMock(return_value=mysql.connector.cursor.MySQLCursor()) try: - insert_pandas(df, conn, "myTable", "MySchema", batch_size=1) + insert_pandas( + df=df, connection=conn, table="myTable", schema="MySchema", batch_size=1 + ) result = True except: result = False assert result + + +@pytest.mark.skip(reason="This test is skipped unconditionally") +def test_sqlite(): + conn = sqlite3.connect("tests/test_db.sqlite3") + connection = SQLConnection(conn=conn) + + df = pd.DataFrame( + { + "id": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + "amount": [ + 111342, + 463463, + 6357, + 435765, + 757456, + 84678, + 34, + 7547, + 74567, + 76, + ], + "dt": [datetime.today() for _ in range(10)], + "strings": ["a", "b", "a", "a", "a", "a", "b", "a", "a", "a"], + } + ) + table = Table("test_table") + table.create_from_df( + df=df, + execute=True, + insert_data=True, + connection=connection, + batch_size=1, + dialect="sqlite", + ) + + query = Query("select * from test_table") + data = connection.fetch(query, dataframe=True) + os.remove("tests/test_db.sqlite3") + data["dt"] = pd.to_datetime(data["dt"]) + data = data.iloc[:10] + df["dt"] = pd.to_datetime(df["dt"]) + + assert [df[i].tolist() for i in df.columns] == [ + data[i].tolist() for i in df.columns + ] diff --git a/tests/test_queries.py b/tests/test_queries.py index 9c95c05..af00b0c 100644 --- a/tests/test_queries.py +++ b/tests/test_queries.py @@ -83,9 +83,7 @@ def test_cte_replacement(): def test_create_table_string(): - expected = ( - "CREATE TABLE myTable ( col1 int, col11 double, col2 bool, col3 varchar )" - ) + expected = "CREATE TABLE IF NOT EXISTS myTable ( col1 int, col11 double, col2 bool, col3 varchar )" with open("tests/queries/test_cte.sql", "r", encoding="utf-8") as f: sql = f.read()