diff --git a/pygadmin/csv_importer.py b/pygadmin/csv_importer.py index db73bab..2a97f14 100644 --- a/pygadmin/csv_importer.py +++ b/pygadmin/csv_importer.py @@ -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() - diff --git a/pygadmin/widgets/csv_import.py b/pygadmin/widgets/csv_import.py index 5717021..a6ae820 100644 --- a/pygadmin/widgets/csv_import.py +++ b/pygadmin/widgets/csv_import.py @@ -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())