CSV import layout

Create a layout in the csv import dialog for creating the table
and create the possibilty of user input
This commit is contained in:
Lea Laux 2021-02-17 14:19:05 +01:00 committed by KDV Admin
parent 9f9fd245c0
commit 7906123f47
2 changed files with 120 additions and 40 deletions

View File

@ -4,7 +4,6 @@ import csv
import re import re
from pygadmin.database_query_executor import DatabaseQueryExecutor from pygadmin.database_query_executor import DatabaseQueryExecutor
from pygadmin.connectionfactory import global_connection_factory
class CSVImporter: class CSVImporter:
@ -13,7 +12,7 @@ class CSVImporter:
assumed data types and inserting all the data. assumed data types and inserting all the data.
""" """
def __init__(self, database_connection, csv_file, delimiter=",", null_type="NULL", table_name=None): def __init__(self, database_connection, csv_file, delimiter=",", null_type="", table_name=None):
# Use the csv file for loading the relevant data. # Use the csv file for loading the relevant data.
self.csv_file = csv_file self.csv_file = csv_file
# Use a delimiter for the csv file, not necessarily ",". # Use a delimiter for the csv file, not necessarily ",".
@ -155,7 +154,7 @@ class CSVImporter:
# Get the table name, so the table name can be used in the create statement. # Get the table name, so the table name can be used in the create statement.
self.get_table_name() self.get_table_name()
# Add the table name to the query. # Add the table name to the query.
create_table_query = "CREATE TABLE {} (".format(self.table_name) create_table_query = "CREATE TABLE {} (\n".format(self.table_name)
# Get the header as start of the csv data, because the columns are defined here. # Get the header as start of the csv data, because the columns are defined here.
header = self.csv_data[0] header = self.csv_data[0]
@ -335,27 +334,3 @@ class CSVImporter:
parameter = '"{}"'.format(parameter) parameter = '"{}"'.format(parameter)
return parameter return parameter
def do_all_the_stuff(self):
"""
Normal persons would call this function "main". This function is only a placeholder to remember me, that I'm
going to need a function for doing all the relevant csv stuff, so the user/rest of the program needs only a
database connection and a name, function call, boom, everything is working (or not, that's a case for an error).
So, strong TODO
"""
pass
# TODO: Check for file existence, parse file with error handling, assume the data type on a very basic level, check for
# create table or insert in existing table, (create table and) insert
if __name__ == "__main__":
csv_importer = CSVImporter(global_connection_factory.get_database_connection("localhost", "testuser", "testdb"),
"/home/sqlea/fl.csv", delimiter=";", table_name="new_test_table")
if csv_importer.check_existence_csv_file() is True:
csv_importer.parse_csv_file()
csv_importer.assume_data_types()
csv_importer.get_create_statement()
csv_importer.create_and_execute_insert_queries()

View File

@ -1,7 +1,7 @@
import sys import sys
import time import time
from PyQt5.QtWidgets import QDialog, QGridLayout, QLabel, QApplication, QPushButton, QMessageBox from PyQt5.QtWidgets import QDialog, QGridLayout, QLabel, QApplication, QPushButton, QMessageBox, QLineEdit
from pygadmin.connectionfactory import global_connection_factory from pygadmin.connectionfactory import global_connection_factory
from pygadmin.csv_importer import CSVImporter from pygadmin.csv_importer import CSVImporter
@ -9,29 +9,99 @@ from pygadmin.widgets.widget_icon_adder import IconAdder
class CSVImportDialog(QDialog): class CSVImportDialog(QDialog):
# TODO: docu """
def __init__(self, database_connection, csv_file, delimiter): Create a dialog for importing a table out of a csv file to a table in the database with all given data in the csv
file. User interaction is necessary for editing the names and data types of the column.
"""
def __init__(self, database_connection, csv_file):
super().__init__() super().__init__()
# Add the pygadmin icon as window icon. # Add the pygadmin icon as window icon.
icon_adder = IconAdder() icon_adder = IconAdder()
icon_adder.add_icon_to_widget(self) icon_adder.add_icon_to_widget(self)
self.csv_importer = CSVImporter(database_connection, csv_file, delimiter, table_name="new_test_table", # TODO: Workaround for delimiter
null_type="") self.csv_importer = CSVImporter(database_connection, csv_file)
# If the csv file exists, initialize the relevant parts of the dialog.
if self.csv_importer.check_existence_csv_file(): if self.csv_importer.check_existence_csv_file():
self.init_ui() self.init_ui()
self.init_grid() self.init_grid()
self.csv_importer.database_query_executor.result_data.connect(self.show_success) self.csv_importer.database_query_executor.result_data.connect(self.show_success)
self.csv_importer.database_query_executor.error.connect(self.show_error) self.csv_importer.database_query_executor.error.connect(self.show_error)
# Show an error for a non existing file.
else: else:
self.init_error_ui(csv_file) self.init_error_ui(csv_file)
def init_ui(self): def init_ui(self):
"""
Initialize the user interface.
"""
# Parse the given csv file.
self.csv_importer.parse_csv_file() self.csv_importer.parse_csv_file()
# Get the data types of the given csv file.
self.csv_importer.assume_data_types() self.csv_importer.assume_data_types()
self.create_statement_label = QLabel(self.csv_importer.get_create_statement()) # Get the create statement of the given csv file based on the column names in the file and the data types.
create_statement = self.csv_importer.get_create_statement()
# Start the statement with a "CREATE TABLE".
self.create_table_start_label = QLabel("CREATE TABLE ")
# Get a line edit with the name of the table.
self.table_name_line_edit = QLineEdit(self.csv_importer.table_name)
# Open the definition part of the create statement with an (.
self.open_label = QLabel("(")
# Get the list of column definition parameters by splitting the create statement at every newline.
column_definition_list = create_statement.split("\n")
# Delete the first element, because this element does only contain a "CREATE TABLE".
del column_definition_list[0]
# Delete the last element as closing part of the statement.
del column_definition_list[len(column_definition_list)-1]
# Split the column definition at commas.
column_definition_list = [column_definition.replace(",", "") for column_definition in column_definition_list]
# Create a list for the column line edits, so there is a class-wide access to this list.
self.column_line_edit_list = []
# Process every column in the list.
for column in column_definition_list:
# Split the column at whitespaces, so the
identifier_list = column.split(" ")
# Get the index of the last element based on the length of the identifier list.
last_element_index = len(identifier_list)-1
# The last item is the column data type, which is only one word with any whitespaces.
column_data_type = identifier_list[last_element_index]
# Delete the last element from the list, because it is not necessary anymore and possibly disturbs the
# process of getting the column name.
del identifier_list[last_element_index]
# Define an empty string for the column name for appending the name in the process.
column_name = ""
# If the length of the list is now 1, the standard case is the correct one: The first element of the list is
# the name of the column, plain and simple.
if len(identifier_list) == 1:
column_name = identifier_list[0]
# The edge case is for column names with a whitespace in the column name. Every part of the name is split
# at the whitespace before, so it will be whole again.
else:
for item in identifier_list:
column_name = "{} {}".format(column_name, item)
# Create a line edit for the column name.
column_name_line_edit = QLineEdit(column_name)
# Create a line edit for the column data type.
column_data_type_line_edit = QLineEdit(column_data_type)
# Append the two line edits to the list of all line edits for further usage.
self.column_line_edit_list.append((column_name_line_edit, column_data_type_line_edit))
# Define a label for closing the statement.
self.close_label = QLabel(");")
# Under construction TODO
self.insert_button = QPushButton("Insert") self.insert_button = QPushButton("Insert")
self.create_button = QPushButton("Create") self.create_button = QPushButton("Create")
self.insert_button.clicked.connect(self.insert_data) self.insert_button.clicked.connect(self.insert_data)
@ -39,14 +109,44 @@ class CSVImportDialog(QDialog):
self.show() self.show()
def init_grid(self): def init_grid(self):
"""
Initialize the grid part of the layout.
"""
# Get the grid layout.
grid_layout = QGridLayout(self) grid_layout = QGridLayout(self)
grid_layout.addWidget(self.create_statement_label, 0, 0)
grid_layout.addWidget(self.insert_button, 0, 1) # Place the first three widgets: The label for the beginning of the CREATE, the name and the opening of the
grid_layout.addWidget(self.create_button, 0, 2) # table.
grid_layout.addWidget(self.create_table_start_label, 0, 0)
grid_layout.addWidget(self.table_name_line_edit, 0, 1)
grid_layout.addWidget(self.open_label, 0, 2)
# Define a line count for placing the elements of the column line edit list.
line_edit_count = 1
# Place all components of the column line edit list.
for line_edits in self.column_line_edit_list:
# Place the first element of the tuple, the name of the column.
grid_layout.addWidget(line_edits[0], line_edit_count, 0)
# Place the second element of the tuple, the data type of the column on the right of the name.
grid_layout.addWidget(line_edits[1], line_edit_count, 1)
# Increment the count, so the next tuple of line edits is placed under those ones.
line_edit_count += 1
# Place the close label at the end of CREATE
grid_layout.addWidget(self.close_label, line_edit_count, 0)
# Set the spacing of the grid.
grid_layout.setSpacing(10) grid_layout.setSpacing(10)
# Set the layout to the grid layout.
self.setLayout(grid_layout) self.setLayout(grid_layout)
def init_error_ui(self, csv_file): def init_error_ui(self, csv_file):
"""
Initialize the user interface for the error case and show the name of the invalid csv file.
"""
# Get the layout as grid layout. # Get the layout as grid layout.
grid_layout = QGridLayout(self) grid_layout = QGridLayout(self)
# Add a label with an error. # Add a label with an error.
@ -58,15 +158,20 @@ class CSVImportDialog(QDialog):
self.setWindowTitle("File Error") self.setWindowTitle("File Error")
self.show() self.show()
def create_table(self):
"""
TODO: Build create statement and use the csv importer for execution
"""
self.csv_importer.create_table_for_csv_data()
# under construction: TODO
def insert_data(self): def insert_data(self):
begin = time.time() begin = time.time()
self.csv_importer.create_and_execute_insert_queries() self.csv_importer.create_and_execute_insert_queries()
end = time.time() end = time.time()
print("Runtime: {}".format(end-begin)) print("Runtime: {}".format(end-begin))
def create_table(self):
self.csv_importer.create_table_for_csv_data()
def show_success(self, result): def show_success(self, result):
QMessageBox.information(self, "Success", "The result is {}".format(result)) QMessageBox.information(self, "Success", "The result is {}".format(result))
@ -78,6 +183,6 @@ class CSVImportDialog(QDialog):
if __name__ == "__main__": if __name__ == "__main__":
app = QApplication(sys.argv) app = QApplication(sys.argv)
csv_import = CSVImportDialog(global_connection_factory.get_database_connection("localhost", "testuser", "testdb"), csv_import = CSVImportDialog(global_connection_factory.get_database_connection("localhost", "testuser", "testdb"),
"/home/sqlea/fl.csv", ",") "/home/sqlea/test.csv")
sys.exit(app.exec()) sys.exit(app.exec())