Added multiple drop/delete functionality for the table constraints. Fixes #3900
parent
553eeb034d
commit
6e5dbf7beb
|
@ -32,6 +32,7 @@ Bug fixes
|
|||
| `Issue #3495 <https://redmine.postgresql.org/issues/3495>`_ - Fixed an issue where the query tool unable to load the file which contains the BOM marker.
|
||||
| `Issue #3523 <https://redmine.postgresql.org/issues/3523>`_ - Fixed an issue where right-clicking a browser object does not apply to the object on which right-click was fired.
|
||||
| `Issue #3645 <https://redmine.postgresql.org/issues/3645>`_ - Ensure that the start and end date should be deleted when clear the selection for pgAgent Job.
|
||||
| `Issue #3900 <https://redmine.postgresql.org/issues/3900>`_ - Added multiple drop/delete functionality for the table constraints.
|
||||
| `Issue #3947 <https://redmine.postgresql.org/issues/3947>`_ - Fixed copy-paste row issues in View/Edit Data.
|
||||
| `Issue #3972 <https://redmine.postgresql.org/issues/3972>`_ - Modified keyboard shortcuts in Query Tool for OSX native support.
|
||||
| `Issue #3988 <https://redmine.postgresql.org/issues/3988>`_ - Fixed cursor disappeared issue in the query editor for some of the characters when zoomed out.
|
||||
|
|
|
@ -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/<int:gid>/<int:sid>/<int:did>/<int:scid>/<int:tid>/',
|
||||
methods=['DELETE'])
|
||||
@blueprint.route('/delete/<int:gid>/<int:sid>/<int:did>/<int:scid>/<int:tid>/',
|
||||
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.")
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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'),
|
||||
|
|
Loading…
Reference in New Issue