CSV export improvement: Full table

Export the full table to a CSV file in the context menu for a table node
in the tree model. Use the csv exporter as refactored tool. The exporter
can work with database parameters including the name of the table or the
resulting data list. TODO: Documentation
This commit is contained in:
Lea Laux 2021-02-24 13:03:59 +01:00 committed by KDV Admin
parent e1e13376a9
commit 883adeaaff
3 changed files with 172 additions and 53 deletions

145
pygadmin/csv_exporter.py Normal file
View File

@ -0,0 +1,145 @@
import logging
from PyQt5.QtWidgets import QFileDialog, QMessageBox
from pygadmin.database_query_executor import DatabaseQueryExecutor
from pygadmin.connectionfactory import global_connection_factory
class CSVExporter:
"""
Create a class for exporting the current results to a CSV file. TODO: Docu
"""
def __init__(self, parent, data_list, database_connection_parameters=None, table_name=None):
"""
Get the parent for assigning the file dialog to a widget and the data list for the data, which will be saved.
"""
# If the data list is None and the database connection parameters are None, there is no way to get the required
# data for the csv file.
if data_list is None and database_connection_parameters is None:
# Show the error to the user and end the initialization.
QMessageBox.critical(parent, "Data Error", "A data source for exporting to CSV is not given.")
return
# Define the parent, the data list and the file name as attributes.
self.parent = parent
self.data_list = data_list
self.file_name = None
# If the data list is None, the required data needs to be collected.
if self.data_list is None:
# Prepare the data list with building the query and preparing the database query executor.
self.prepare_data_list(database_connection_parameters, table_name)
# Set the success attribute to False, because the csv export is still in process and not successful at this
# point in the program.
self.success = False
def prepare_data_list(self, database_connection_parameters, table_name):
"""
Prepare the relevant parts for getting the data list with the database connection, the database query executor
and the database query.
"""
database_connection = self.get_database_connection(database_connection_parameters)
if database_connection is None:
return
query = "SELECT * FROM {};".format(table_name)
self.database_query_executor = DatabaseQueryExecutor()
self.database_query_executor.result_data.connect(self.get_result_data_list)
self.database_query_executor.database_connection = database_connection
self.database_query_executor.database_query = query
def get_database_connection(self, database_connection_parameters):
database_connection = global_connection_factory.get_database_connection(database_connection_parameters["host"],
database_connection_parameters["user"],
database_connection_parameters[
"database"],
database_connection_parameters["port"])
if database_connection is None or database_connection is False:
QMessageBox.critical(self.parent, "Database Connection Fail", "The connection to the database failed, "
"please check the log for further "
"information.")
return None
return database_connection
def get_result_data_list(self, data_list):
if data_list:
self.data_list = data_list
self.success = True
self.export_and_save_csv_data()
def get_file_name_by_file_dialog(self):
"""
Create a file dialog for activating the csv export.
"""
# Get a csv file with the default name result.csv and the file type csv.
file_dialog_with_name_and_type = QFileDialog.getSaveFileName(self.parent, "Save File", "result.csv",
"CSV (*.csv)")
# Get the file name.
file_name = file_dialog_with_name_and_type[0]
# If the file name is not an empty string, return the file name, because in this case, the user has entered one.
if file_name != "":
return file_name
# Inform the user in the log about the abort.
else:
logging.info("The current file saving process was aborted by the user, so the current result as csv file"
" is not saved.")
# Return False, because there is no file name.
return False
def export_result_to_csv(self, file_name):
"""
Export the result data to csv with the file name. Get the data out of the table model.
"""
# Open the given file in write mode.
with open(file_name, "w") as file_to_save:
# Get through every data row in the data list.
for data_row in self.data_list:
# Get through every value in the data row.
for data_value_counter in range(len(data_row)):
# Write every value.
file_to_save.write(str(data_row[data_value_counter]))
# If the value is not the last one, append a comma for comma separated value.
if data_value_counter != len(data_row) - 1:
file_to_save.write(",")
# Write a newline at the end of a data row.
file_to_save.write("\n")
def export_and_save_csv_data(self):
"""
Activate the export and save of the csv data.
"""
if self.file_name is None:
# Get the file name with a file dialog.
self.file_name = self.get_file_name_by_file_dialog()
# If the file name is False, the process of saving the file has been aborted.
if self.file_name is False:
# End the function with a return.
return
if self.data_list is None:
self.database_query_executor.submit_and_execute_query()
return
# Save the current query result data.
self.export_result_to_csv(self.file_name)
return True

View File

@ -10,6 +10,7 @@ from PyQt5.QtWidgets import QWidget, QGridLayout, QPushButton, QTableView, QMess
QCheckBox, QLabel, qApp
from pygadmin.connectionfactory import global_connection_factory
from pygadmin.csv_exporter import CSVExporter
from pygadmin.models.tablemodel import TableModel
from pygadmin.configurator import global_app_configurator
from pygadmin.models.lexer import SQLLexer
@ -1074,60 +1075,12 @@ class EditorWidget(QWidget, SearchReplaceParent, metaclass=MetaEditor):
Activate the export and save of the csv data.
"""
# Get the file name with a file dialog.
file_name = self.activate_file_dialog_for_csv_export()
# TODO: Docu
csv_exporter = CSVExporter(self, self.table_model.data_list)
success = csv_exporter.export_and_save_csv_data()
# If the file name is None, the process of saving the file has been aborted.
if file_name is None:
# End the function with a return.
return
# Save the current query result data.
self.export_result_to_csv(file_name)
def activate_file_dialog_for_csv_export(self):
"""
Create a file dialog for activating the csv export.
"""
# Get a csv file with the default name result.csv and the file type csv.
file_dialog_with_name_and_type = QFileDialog.getSaveFileName(self, "Save File", "result", "CSV (*.csv)")
# Get the file name.
file_name = file_dialog_with_name_and_type[0]
# If the file name is not an empty string, return the file name, because in this case, the user has entered one.
if file_name != "":
return file_name
# Inform the user in the log about the abort.
else:
logging.info("The current file saving process was aborted by the user, so the current result as csv file"
" is not saved.")
# Return None, because there is no file name.
return None
def export_result_to_csv(self, file_name):
"""
Export the result data to csv with the file name. Get the data out of the table model.
"""
# Open the given file in write mode.
with open(file_name, "w") as file_to_save:
# Get through every data row in the data list.
for data_row in self.table_model.data_list:
# Get through every value in the data row.
for data_value_counter in range(len(data_row)):
# Write every value.
file_to_save.write(str(data_row[data_value_counter]))
# If the value is not the last one, append a comma for comma separated value.
if data_value_counter != len(data_row) - 1:
file_to_save.write(",")
# Write a newline at the end of a data row.
file_to_save.write("\n")
if success:
QMessageBox.information(self, "Export Success", "The csv export was successful.")
def get_explain_analyze_query(self):
"""

View File

@ -8,6 +8,7 @@ from PyQt5.QtWidgets import QWidget, QTreeView, QAbstractItemView, QMessageBox,
from pygadmin.configurator import global_app_configurator
from pygadmin.connectionstore import global_connection_store
from pygadmin.csv_exporter import CSVExporter
from pygadmin.models.treemodel import ServerNode, TablesNode, ViewsNode, SchemaNode, AbstractBaseNode, DatabaseNode, \
TableNode, ViewNode
from pygadmin.widgets.materialized_view_information import MaterializedViewInformationDialog
@ -311,6 +312,8 @@ class TreeWidget(QWidget):
self.context_menu.addAction(show_permission_information_action)
edit_single_values_action = QAction("Edit Single Values", self)
self.context_menu.addAction(edit_single_values_action)
export_full_table_to_csv_action = QAction("Export Full Table As CSV", self)
self.context_menu.addAction(export_full_table_to_csv_action)
# Get the action at the current position of the triggering event.
position_action = self.context_menu.exec_(self.tree_view.viewport().mapToGlobal(position))
@ -334,6 +337,9 @@ class TreeWidget(QWidget):
elif position_action == edit_single_values_action:
self.show_edit_singles_values_dialog(current_selected_node)
elif position_action == export_full_table_to_csv_action:
self.get_full_data_of_current_table_for_csv_export(current_selected_node)
def append_new_connection_parameters_and_node(self):
"""
Get new parameters out of the .yaml file, where all connections are stored, because this function should be
@ -978,3 +984,18 @@ class TreeWidget(QWidget):
"""
self.materialized_view_information_dialog = MaterializedViewInformationDialog(current_node)
def get_full_data_of_current_table_for_csv_export(self, current_node):
# TODO: Docu
self.csv_exporter = CSVExporter(self, None, {"host": current_node.database_connection_parameters["host"],
"user": current_node.database_connection_parameters["user"],
"database":
current_node.database_connection_parameters["database"],
"port": current_node.database_connection_parameters["port"]},
current_node.name)
self.csv_exporter.export_and_save_csv_data()
self.csv_exporter.database_query_executor.result_data.connect(lambda:
QMessageBox.information(self, "Export Success",
"The csv export was "
"successful."))