diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/__init__.py index 3205bb58c..d37c106b8 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/__init__.py @@ -9,6 +9,8 @@ """Implements Constraint Node""" +import json +from flask import request from functools import wraps from pgadmin.utils.driver import get_driver import pgadmin.browser.server_groups.servers.databases as database @@ -132,3 +134,48 @@ def proplist(**kwargs): response=res, status=200 ) + + +@blueprint.route('/obj//////', + methods=['DELETE']) +@blueprint.route('/delete//////', + methods=['DELETE']) +def delete(**kwargs): + """ + Delete multiple constraints under the table. + Args: + **kwargs: + + Returns: + + """ + data = request.form if request.form else json.loads( + request.data, encoding='utf-8') + + if 'delete' in request.base_url: + cmd = {"cmd": "delete"} + else: + cmd = {"cmd": "obj"} + res = [] + module_wise_data = {} + + for d in data['ids']: + if d['_type'] in module_wise_data: + module_wise_data[d['_type']].append(d['id']) + else: + module_wise_data[d['_type']] = [d['id']] + + for name in ConstraintRegistry.registry: + if name in module_wise_data: + module = (ConstraintRegistry.registry[name])['nodeview'] + view = module(**cmd) + request.data = json.dumps({'ids': module_wise_data[name]}) + response = view.delete(**kwargs) + res = json.loads(response.data.decode('utf-8')) + if not res['success']: + return response + + return make_json_response( + success=1, + info=gettext("Constraints dropped.") + ) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/__init__.py index 9f263fb47..58ccb2f0c 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/__init__.py @@ -272,6 +272,9 @@ class CheckConstraintView(PGChildNodeView): tid=tid) status, res = self.conn.execute_dict(SQL) + for row in res['rows']: + row['_type'] = self.node_type + return res['rows'] @check_precondition diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py index c5e6b9959..5204fe635 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py @@ -339,6 +339,9 @@ class ExclusionConstraintView(PGChildNodeView): tid=tid) status, res = self.conn.execute_dict(SQL) + for row in res['rows']: + row['_type'] = self.node_type + return res['rows'] @check_precondition diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/__init__.py index 81eeb067d..503c77e81 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/__init__.py @@ -349,6 +349,9 @@ class ForeignKeyConstraintView(PGChildNodeView): tid=tid) status, res = self.conn.execute_dict(SQL) + for row in res['rows']: + row['_type'] = self.node_type + return res['rows'] @check_precondition diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/__init__.py index 8bd4790fb..05cfe3050 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/__init__.py @@ -359,6 +359,9 @@ class IndexConstraintView(PGChildNodeView): constraint_type=self.constraint_type) status, res = self.conn.execute_dict(SQL) + for row in res['rows']: + row['_type'] = self.node_type + return res['rows'] @check_precondition diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/static/js/constraints.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/static/js/constraints.js index 9239085ee..dea9fcb4f 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/static/js/constraints.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/static/js/constraints.js @@ -22,8 +22,8 @@ define('pgadmin.node.constraints', [ label: gettext('Constraints'), type: 'coll-constraints', columns: ['name', 'comment'], - canDrop: false, - canDropCascade: false, + canDrop: true, + canDropCascade: true, }); } diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/tests/test_constraint_delete_multiple.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/tests/test_constraint_delete_multiple.py new file mode 100644 index 000000000..d3b3905e0 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/tests/test_constraint_delete_multiple.py @@ -0,0 +1,137 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2020, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +import uuid +import json + +from pgadmin.browser.server_groups.servers.databases.schemas.tests import \ + utils as schema_utils +from pgadmin.browser.server_groups.servers.databases.tests import utils as \ + database_utils +from pgadmin.utils.route import BaseTestGenerator +from regression import parent_node_dict +from regression.python_test_utils import test_utils as utils +from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \ + import utils as tables_utils +from pgadmin.browser.server_groups.servers.databases.schemas.tables.\ + constraints.check_constraint.tests import utils as chk_constraint_utils +from pgadmin.browser.server_groups.servers.databases.schemas.tables.\ + constraints.exclusion_constraint.tests import utils as exclusion_utils +from pgadmin.browser.server_groups.servers.databases.schemas.tables.\ + constraints.foreign_key.tests import utils as fk_utils +from pgadmin.browser.server_groups.servers.databases.schemas.tables.\ + constraints.index_constraint.tests import utils as index_constraint_utils + + +class ConstraintDeleteMultipleTestCase(BaseTestGenerator): + """This class will delete constraints under table node.""" + scenarios = [ + # Fetching default URL for table node. + ('Delete Constraints', dict(url='/browser/constraints/obj/')) + ] + + def setUp(self): + self.db_name = parent_node_dict["database"][-1]["db_name"] + schema_info = parent_node_dict["schema"][-1] + self.server_id = schema_info["server_id"] + self.db_id = schema_info["db_id"] + db_con = database_utils.connect_database(self, utils.SERVER_GROUP, + self.server_id, self.db_id) + if not db_con['data']["connected"]: + raise Exception("Could not connect to database to add a table.") + self.schema_id = schema_info["schema_id"] + self.schema_name = schema_info["schema_name"] + schema_response = schema_utils.verify_schemas(self.server, + self.db_name, + self.schema_name) + if not schema_response: + raise Exception("Could not find the schema to add a table.") + self.table_name = "table_constraint_delete_%s" % \ + (str(uuid.uuid4())[1:8]) + self.table_id = tables_utils.create_table(self.server, + self.db_name, + self.schema_name, + self.table_name) + # Create Check Constraints + self.check_constraint_name = "test_constraint_delete_%s" % \ + (str(uuid.uuid4())[1:8]) + self.check_constraint_id = \ + chk_constraint_utils.create_check_constraint( + self.server, self.db_name, self.schema_name, self.table_name, + self.check_constraint_name) + + self.check_constraint_name_1 = "test_constraint_delete1_%s" % ( + str(uuid.uuid4())[1:8]) + self.check_constraint_id_1 = \ + chk_constraint_utils.create_check_constraint( + self.server, self.db_name, self.schema_name, self.table_name, + self.check_constraint_name_1) + + # Create Exclusion Constraint + self.exclustion_constraint_name = "test_exclusion_get_%s" % ( + str(uuid.uuid4())[1:8]) + self.exclustion_constraint_id = \ + exclusion_utils.create_exclusion_constraint( + self.server, self.db_name, self.schema_name, self.table_name, + self.exclustion_constraint_name + ) + + # Create Foreign Key + self.foreign_table_name = "foreign_table_foreignkey_get_%s" % \ + (str(uuid.uuid4())[1:8]) + self.foreign_table_id = tables_utils.create_table( + self.server, self.db_name, self.schema_name, + self.foreign_table_name) + self.foreign_key_name = "test_foreignkey_get_%s" % \ + (str(uuid.uuid4())[1:8]) + self.foreign_key_id = fk_utils.create_foreignkey( + self.server, self.db_name, self.schema_name, self.table_name, + self.foreign_table_name) + + # Create Primary Key + self.primary_key_name = "test_primary_key_get_%s" % \ + (str(uuid.uuid4())[1:8]) + self.primary_key_id = \ + index_constraint_utils.create_index_constraint( + self.server, self.db_name, self.schema_name, self.table_name, + self.primary_key_name, "PRIMARY KEY") + + # Create Unique Key constraint + self.unique_constraint_name = "test_unique_constraint_get_%s" % ( + str(uuid.uuid4())[1:8]) + + self.unique_constraint_id = \ + index_constraint_utils.create_index_constraint( + self.server, self.db_name, self.schema_name, self.table_name, + self.unique_constraint_name, "UNIQUE") + + def runTest(self): + """This function will delete constraints under table node.""" + data = {'ids': [ + {'id': self.check_constraint_id, '_type': 'check_constraint'}, + {'id': self.check_constraint_id_1, '_type': 'check_constraint'}, + {'id': self.exclustion_constraint_id, + '_type': 'exclustion_constraint'}, + {'id': self.foreign_key_id, '_type': 'foreign_key'}, + {'id': self.primary_key_id, '_type': 'index_constraint'}, + {'id': self.unique_constraint_id, '_type': 'index_constraint'} + ]} + response = self.tester.delete(self.url + str(utils.SERVER_GROUP) + + '/' + str(self.server_id) + '/' + + str(self.db_id) + '/' + + str(self.schema_id) + '/' + + str(self.table_id) + '/', + data=json.dumps(data), + content_type='html/json', + follow_redirects=True) + self.assertEquals(response.status_code, 200) + + def tearDown(self): + # Disconnect the database + database_utils.disconnect_database(self, self.server_id, self.db_id) diff --git a/web/pgadmin/browser/static/js/collection.js b/web/pgadmin/browser/static/js/collection.js index b3bf7fa62..54f583765 100644 --- a/web/pgadmin/browser/static/js/collection.js +++ b/web/pgadmin/browser/static/js/collection.js @@ -354,7 +354,13 @@ define([ msg = undefined, title = undefined; - _.each(sel_row_models, function(r){ sel_rows.push(r.id); }); + if (node.type && node.type == 'coll-constraints') { + // In order to identify the constraint type, the type should be passed to the server + sel_rows = sel_row_models.map(row => ({id: row.get('oid'), _type: row.get('_type')})); + } + else { + sel_rows = sel_row_models.map(row => row.id); + } if (sel_rows.length === 0) { Alertify.alert(gettext('Drop Multiple'),