Added a primitive run multiple sql statements, that does NOT support plsql
This commit is contained in:
parent
fd1b2b796a
commit
65d9dd809d
@ -33,7 +33,8 @@ class DBAdapter:
|
|||||||
self._engine: sq.Engine = sq.create_engine(connection_string)
|
self._engine: sq.Engine = sq.create_engine(connection_string)
|
||||||
logger.info('Database initialized')
|
logger.info('Database initialized')
|
||||||
|
|
||||||
def _read_and_sql_file_and_strip_for_comments(self, filename: str):
|
|
||||||
|
def _read_and_sql_file_and_strip_for_comments(self, filename: str) -> str:
|
||||||
query: str
|
query: str
|
||||||
self._logger.info(f'Reading file {filename}')
|
self._logger.info(f'Reading file {filename}')
|
||||||
with open(filename, 'r') as f:
|
with open(filename, 'r') as f:
|
||||||
@ -42,6 +43,9 @@ class DBAdapter:
|
|||||||
query = sqlparse.format(query, strip_comments=True)
|
query = sqlparse.format(query, strip_comments=True)
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
def _split_query_to_singular_queries(self, query) -> list[str]:
|
||||||
|
return sqlparse.split(query)
|
||||||
|
|
||||||
def _set_transaction_readonly(self, conn: sq.Connection):
|
def _set_transaction_readonly(self, conn: sq.Connection):
|
||||||
self._logger.info('Setting transaction to readonly.')
|
self._logger.info('Setting transaction to readonly.')
|
||||||
if not conn.in_transaction():
|
if not conn.in_transaction():
|
||||||
@ -66,7 +70,23 @@ class DBAdapter:
|
|||||||
case _:
|
case _:
|
||||||
raise Exception(f'Database type {self.database_config.type} is not supported for readonly transactions')
|
raise Exception(f'Database type {self.database_config.type} is not supported for readonly transactions')
|
||||||
|
|
||||||
|
def _verify_singular_query(self, query: str):
|
||||||
|
self._logger.info(f'Verifying query: {query}')
|
||||||
|
if len(self._split_query_to_singular_queries(query)) > 1:
|
||||||
|
self._logger.critical(f'Multiple queries found for query: {query}')
|
||||||
|
raise Exception(f'Multiple queries found in {query}')
|
||||||
|
|
||||||
def run_query(self, query: str, read_only = True) -> sq.CursorResult:
|
def run_query(self, query: str, read_only = True) -> sq.CursorResult:
|
||||||
|
"""
|
||||||
|
Runs a single SQL query and returns the result as a CursorResult.
|
||||||
|
If more than one query, throws an error
|
||||||
|
:param query: the query to run
|
||||||
|
:param read_only: if the transaction is read-only
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
self._verify_singular_query(query)
|
||||||
|
|
||||||
result: sq.CursorResult
|
result: sq.CursorResult
|
||||||
self._logger.info(f'Running query: "{query}"')
|
self._logger.info(f'Running query: "{query}"')
|
||||||
with self._engine.connect() as conn:
|
with self._engine.connect() as conn:
|
||||||
@ -91,6 +111,15 @@ class DBAdapter:
|
|||||||
return self.run_query(query, read_only)
|
return self.run_query(query, read_only)
|
||||||
|
|
||||||
def run_sql_file_export_to_csv(self, schema: str | None = None, input_name: str = "query.sql", output_name: str = "export.csv", read_only = True):
|
def run_sql_file_export_to_csv(self, schema: str | None = None, input_name: str = "query.sql", output_name: str = "export.csv", read_only = True):
|
||||||
|
"""
|
||||||
|
Runs a single SQL query and creates a csv file with the given output name and resulting contents.
|
||||||
|
If more than one query, throws an error
|
||||||
|
:param schema: the schema to use
|
||||||
|
:param input_name: the name of the sql file to use
|
||||||
|
:param output_name: the name of the csv file to create
|
||||||
|
:param read_only: if the transaction is read-only
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
result: pd.DataFrame
|
result: pd.DataFrame
|
||||||
|
|
||||||
query = self._read_and_sql_file_and_strip_for_comments(input_name)
|
query = self._read_and_sql_file_and_strip_for_comments(input_name)
|
||||||
@ -105,6 +134,8 @@ class DBAdapter:
|
|||||||
|
|
||||||
def _extract_dataframe(self, conn: sq.Connection, query: str, read_only: bool, schema: str | None = None) -> pd.DataFrame:
|
def _extract_dataframe(self, conn: sq.Connection, query: str, read_only: bool, schema: str | None = None) -> pd.DataFrame:
|
||||||
result: pd.DataFrame
|
result: pd.DataFrame
|
||||||
|
self._verify_singular_query(query)
|
||||||
|
|
||||||
with conn.begin():
|
with conn.begin():
|
||||||
self._logger.info("Starting transaction")
|
self._logger.info("Starting transaction")
|
||||||
try:
|
try:
|
||||||
@ -133,3 +164,33 @@ class DBAdapter:
|
|||||||
output_file_name = f'{base_output_name}{municipality.name}.csv'
|
output_file_name = f'{base_output_name}{municipality.name}.csv'
|
||||||
result.to_csv(output_file_name, index=False, sep=';')
|
result.to_csv(output_file_name, index=False, sep=';')
|
||||||
self._logger.info(f'Created file {output_file_name}')
|
self._logger.info(f'Created file {output_file_name}')
|
||||||
|
|
||||||
|
def run_sql_file_multiple_statements(self, filename: str = "query.sql", read_only = False):
|
||||||
|
"""
|
||||||
|
Runs an SQL file, supports multiple statements, does not support plsql.
|
||||||
|
If any statements fail, throws an error and rolls back.
|
||||||
|
:param filename: the name of the sql file to use
|
||||||
|
:param read_only: if the transaction is read-only
|
||||||
|
:return: Nothing
|
||||||
|
"""
|
||||||
|
raw_query = self._read_and_sql_file_and_strip_for_comments(filename)
|
||||||
|
queries = self._split_query_to_singular_queries(raw_query)
|
||||||
|
self._logger.info(queries)
|
||||||
|
self._logger.info(f'Running {len(queries)} queries')
|
||||||
|
with self._engine.connect() as conn:
|
||||||
|
with conn.begin():
|
||||||
|
self._logger.info("Starting transaction")
|
||||||
|
try:
|
||||||
|
if read_only:
|
||||||
|
self._set_transaction_readonly(conn)
|
||||||
|
for index, query in enumerate(queries):
|
||||||
|
start = time.time()
|
||||||
|
conn.execute(sq.text(query))
|
||||||
|
end = time.time()
|
||||||
|
self._logger.info(f'({index + 1} / {len(queries)}) Query took {(end - start):.4f} seconds ({query})')
|
||||||
|
conn.commit()
|
||||||
|
except Exception as e:
|
||||||
|
self._logger.info(f'Transaction rollback')
|
||||||
|
conn.rollback()
|
||||||
|
raise e
|
||||||
|
self._logger.info(f'Transaction commited')
|
||||||
|
|||||||
4
main.py
4
main.py
@ -11,4 +11,6 @@ config = Config()
|
|||||||
keepass = KeePass(config.kee_pass, logger)
|
keepass = KeePass(config.kee_pass, logger)
|
||||||
|
|
||||||
db_adapter = DBAdapter(keepass, config.database, logger)
|
db_adapter = DBAdapter(keepass, config.database, logger)
|
||||||
db_adapter.run_sql_file_export_to_csv_multiple_schemas([Municipality('test', '123456789', 'op_test', '123')])
|
#db_adapter.run_sql_file_export_to_csv_multiple_schemas([Municipality('test', '123456789', 'op_test', '123')])
|
||||||
|
|
||||||
|
db_adapter.run_sql_file_multiple_statements()
|
||||||
Loading…
x
Reference in New Issue
Block a user