From 43696509722c55b67e4844aa3a68b0e2d53874be Mon Sep 17 00:00:00 2001 From: Lea Laux Date: Tue, 15 Dec 2020 15:59:19 +0100 Subject: [PATCH] Add support for materializied views Show materializied views of a database in an own dialog, available through the context menu for database nodes. --- .../widgets/materialized_view_information.py | 126 ++++++++++++++++++ pygadmin/widgets/tree.py | 13 ++ 2 files changed, 139 insertions(+) create mode 100644 pygadmin/widgets/materialized_view_information.py diff --git a/pygadmin/widgets/materialized_view_information.py b/pygadmin/widgets/materialized_view_information.py new file mode 100644 index 0000000..3044303 --- /dev/null +++ b/pygadmin/widgets/materialized_view_information.py @@ -0,0 +1,126 @@ +import logging + +from PyQt5.QtWidgets import QDialog, QGridLayout, QLabel, QTableView, QMessageBox + +from pygadmin.connectionfactory import global_connection_factory +from pygadmin.database_query_executor import DatabaseQueryExecutor +from pygadmin.models.tablemodel import TableModel +from pygadmin.models.treemodel import DatabaseNode + + +class MaterializedViewInformationDialog(QDialog): + """ + Create a dialog for showing information about the materialized views of a database node. + """ + + def __init__(self, selected_database_node): + super().__init__() + self.setModal(True) + + # Continue with the normal initialization of the dialog, if the instance is correct. + if isinstance(selected_database_node, DatabaseNode): + self.selected_node = selected_database_node + self.init_ui() + self.init_grid() + + # Show an error in the log and the UI. + else: + logging.error("The given node {} is not a Table, View or Database node. As a consequence, the specific " + "actions for checking permissions are not available.".format(selected_database_node)) + + self.init_error_ui() + + def init_ui(self): + """ + Initialize a user interface. + """ + + # Create a table model and table view for showing the resulting data. + self.table_model = TableModel([]) + self.table_view = QTableView() + self.table_view.setModel(self.table_model) + + # Prepare the database connection parameters for further usage in the database query executor. + database_connection_parameters = self.selected_node.database_connection_parameters + self.database_connection = global_connection_factory.get_database_connection( + database_connection_parameters["host"], + database_connection_parameters["user"], + database_connection_parameters["database"], + database_connection_parameters["port"], + database_connection_parameters["timeout"]) + + # Create the database query executor for getting the materialized views by a query. + self.database_query_executor = DatabaseQueryExecutor() + # Connect the signal for the result with displaying the result data. + self.database_query_executor.result_data.connect(self.process_result_data) + # Connect the signal for an error with displaying information about an error. + self.database_query_executor.error.connect(self.process_error_message) + + # Get the materialized views. + self.get_materialized_views() + + # Adjust the size of the dialog. + self.setMaximumSize(720, 300) + self.showMaximized() + self.setWindowTitle("Materialized views for {}".format(self.selected_node.name)) + self.show() + + def init_grid(self): + """ + Initialize the grid layout. + """ + + grid_layout = QGridLayout(self) + grid_layout.addWidget(self.table_view) + + grid_layout.setSpacing(10) + self.setLayout(grid_layout) + + def init_error_ui(self): + """ + Use a small UI for the error case of a wrong node instance as input parameter. + """ + + # Get the layout as grid layout. + grid_layout = QGridLayout(self) + # Add a label with an error. + grid_layout.addWidget(QLabel("The given node is not a Database node, so materialized views cannot be " + "shown."), 0, 0) + self.setLayout(grid_layout) + self.setMaximumSize(10, 100) + self.showMaximized() + # Set the title to an error title. + self.setWindowTitle("Node Input Error") + self.show() + + def get_materialized_views(self): + """ + Get the materialized views of a database node based on a query. + """ + + # Define the query: Get the information of pg_matviews. + database_query = "SELECT * FROM pg_matviews;" + # Set the relevant parameters of the query executor. + self.database_query_executor.database_connection = self.database_connection + self.database_query_executor.database_query = database_query + # Execute! + self.database_query_executor.submit_and_execute_query() + + def process_result_data(self, data_list): + """ + Process the result data: Show the data list in the table model. + """ + + self.table_model.refresh_data_list(data_list) + self.table_view.resizeColumnsToContents() + + def process_error_message(self, error_message): + """ + Process the error message with a log entry and an error message box. + """ + + logging.error("During the query execution, an error occurred: {}".format(error_message)) + QMessageBox.critical(self, "Information Query Error", "The query for getting the information could not" + " be executed with the error {}".format(error_message)) + + diff --git a/pygadmin/widgets/tree.py b/pygadmin/widgets/tree.py index 993d3bd..4463cba 100644 --- a/pygadmin/widgets/tree.py +++ b/pygadmin/widgets/tree.py @@ -10,6 +10,7 @@ from pygadmin.configurator import global_app_configurator from pygadmin.connectionstore import global_connection_store from pygadmin.models.treemodel import ServerNode, TablesNode, ViewsNode, SchemaNode, AbstractBaseNode, DatabaseNode, \ TableNode, ViewNode +from pygadmin.widgets.materialized_view_information import MaterializedViewInformationDialog from pygadmin.widgets.node_create_information import NodeCreateInformationDialog from pygadmin.widgets.permission_information import PermissionInformationDialog from pygadmin.widgets.table_edit import TableEditDialog @@ -258,6 +259,8 @@ class TreeWidget(QWidget): self.context_menu.addAction(show_drop_statement_action) show_permission_information_action = QAction("Show Permissions", self) self.context_menu.addAction(show_permission_information_action) + show_materialized_views_action = QAction("Show Materialized Views") + self.context_menu.addAction(show_materialized_views_action) position_action = self.context_menu.exec_(self.tree_view.viewport().mapToGlobal(position)) @@ -271,6 +274,9 @@ class TreeWidget(QWidget): elif position_action == show_permission_information_action: self.show_permission_dialog(current_selected_node) + elif position_action == show_materialized_views_action: + self.show_materialized_views_of_database_node(current_selected_node) + # Check for a view node. if isinstance(current_selected_node, ViewNode): show_create_statement_action = QAction("Show Create Statement", self) @@ -965,3 +971,10 @@ class TreeWidget(QWidget): # the given drop statement. self.parent().parent().load_editor_with_connection_and_query(parameters_current_node, optional_close_and_drop_statement) + + def show_materialized_views_of_database_node(self, current_node): + """ + Show a dialog with the materialized views of the given node. + """ + + self.materialized_view_information_dialog = MaterializedViewInformationDialog(current_node)