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:
		@@ -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()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user