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
from pygadmin.database_query_executor import DatabaseQueryExecutor
from pygadmin.connectionfactory import global_connection_factory
class CSVImporter:
@ -13,7 +12,7 @@ class CSVImporter:
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.
self.csv_file = csv_file
# 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.
self.get_table_name()
# 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.
header = self.csv_data[0]
@ -335,27 +334,3 @@ class CSVImporter:
parameter = '"{}"'.format(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 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.csv_importer import CSVImporter
@ -9,29 +9,99 @@ from pygadmin.widgets.widget_icon_adder import IconAdder
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__()
# Add the pygadmin icon as window icon.
icon_adder = IconAdder()
icon_adder.add_icon_to_widget(self)
self.csv_importer = CSVImporter(database_connection, csv_file, delimiter, table_name="new_test_table",
null_type="")
# TODO: Workaround for delimiter
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():
self.init_ui()
self.init_grid()
self.csv_importer.database_query_executor.result_data.connect(self.show_success)
self.csv_importer.database_query_executor.error.connect(self.show_error)
# Show an error for a non existing file.
else:
self.init_error_ui(csv_file)
def init_ui(self):
"""
Initialize the user interface.
"""
# Parse the given csv file.
self.csv_importer.parse_csv_file()
# Get the data types of the given csv file.
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.create_button = QPushButton("Create")
self.insert_button.clicked.connect(self.insert_data)
@ -39,14 +109,44 @@ class CSVImportDialog(QDialog):
self.show()
def init_grid(self):
"""
Initialize the grid part of the layout.
"""
# Get the grid layout.
grid_layout = QGridLayout(self)
grid_layout.addWidget(self.create_statement_label, 0, 0)
grid_layout.addWidget(self.insert_button, 0, 1)
grid_layout.addWidget(self.create_button, 0, 2)
# Place the first three widgets: The label for the beginning of the CREATE, the name and the opening of the
# 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)
# Set the layout to the grid layout.
self.setLayout(grid_layout)
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.
grid_layout = QGridLayout(self)
# Add a label with an error.
@ -58,15 +158,20 @@ class CSVImportDialog(QDialog):
self.setWindowTitle("File Error")
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):
begin = time.time()
self.csv_importer.create_and_execute_insert_queries()
end = time.time()
print("Runtime: {}".format(end-begin))
def create_table(self):
self.csv_importer.create_table_for_csv_data()
def show_success(self, result):
QMessageBox.information(self, "Success", "The result is {}".format(result))
@ -78,6 +183,6 @@ class CSVImportDialog(QDialog):
if __name__ == "__main__":
app = QApplication(sys.argv)
csv_import = CSVImportDialog(global_connection_factory.get_database_connection("localhost", "testuser", "testdb"),
"/home/sqlea/fl.csv", ",")
"/home/sqlea/test.csv")
sys.exit(app.exec())