Add support for dropping multiple objects at once from the collection Properties panel. Fixes #1513

This commit is contained in:
Khushboo Vashi 2018-10-31 10:30:36 +00:00 committed by Dave Page
parent 3359a0de7a
commit f17979141c
124 changed files with 5969 additions and 1315 deletions

View File

@ -31,11 +31,17 @@ You can use icons in the *Sessions* table to review or control the state of a se
.. image:: images/main_properties_table.png .. image:: images/main_properties_table.png
:alt: Properties panel :alt: Properties panel
The *Properties* tab displays information about the object selected. Click the *Edit* icon in the toolbar under the browser tabs to launch the *Properties* dialog for the selected object. The *Properties* tab displays information about the object selected.
Click the *Delete* icon in the toolbar under the browser tab to delete the selected objects in the Properties panel.
Click the *Drop Cascade* icon in the toolbar under the browser tab to delete the selected objects and all dependent objects in the Properties panel.
.. image:: images/main_properties_icons.png .. image:: images/main_properties_icons.png
:alt: Object editor icon :alt: Object editor icon
Click the *Edit* icon in the toolbar under the browser tabs to launch the *Properties* dialog for the selected object.
To preserve any changes to the *Properties* dialog, click the *Save* icon; your modifications will be displayed in the updated *Properties* tab. To preserve any changes to the *Properties* dialog, click the *Save* icon; your modifications will be displayed in the updated *Properties* tab.
.. image:: images/main_properties_edit.png .. image:: images/main_properties_edit.png
@ -136,4 +142,4 @@ The *Dependents* tab displays a table of objects that depend on the object curre
Additional tabs open when you access the extended functionality offered by pgAdmin tools (such as the Query tool, Debugger, or SQL editor). Use the close icon (X) located in the upper-right corner of each tab to close the tab when you are finished using the tool. Like permanent tabs, these tabs may be repositioned in the pgAdmin client window. Additional tabs open when you access the extended functionality offered by pgAdmin tools (such as the Query tool, Debugger, or SQL editor). Use the close icon (X) located in the upper-right corner of each tab to close the tab when you are finished using the tool. Like permanent tabs, these tabs may be repositioned in the pgAdmin client window.
By default, each time you open a tool, pgAdmin will open a new browser tab. You can control this behavior by modifying the *Display* node of the *Preferences* dialog for each tool. To open the *Preferences* dialog, select *Preferences* from the *File* menu. By default, each time you open a tool, pgAdmin will open a new browser tab. You can control this behavior by modifying the *Display* node of the *Preferences* dialog for each tool. To open the *Preferences* dialog, select *Preferences* from the *File* menu.

View File

@ -10,7 +10,7 @@ This release contains a number of features and fixes reported since the release
Features Features
******** ********
| `Feature #1513 <https://redmine.postgresql.org/issues/1513>`_ - Add support for dropping multiple objects at once from the collection Properties panel.
Bug fixes Bug fixes
********* *********

View File

@ -242,6 +242,36 @@ def register_browser_preferences(self):
fields=fields fields=fields
) )
self.preference.register(
'keyboard_shortcuts',
'grid_menu_drop_multiple',
gettext('Delete/Drop multiple objects'),
'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {'key_code': 77, 'char': 'm'}
},
category_label=gettext('Keyboard shortcuts'),
fields=fields
)
self.preference.register(
'keyboard_shortcuts',
'grid_menu_drop_cascade_multiple',
gettext('Drop Cascade multiple objects'),
'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {'key_code': 85, 'char': 'u'}
},
category_label=gettext('Keyboard shortcuts'),
fields=fields
)
self.preference.register( self.preference.register(
'keyboard_shortcuts', 'keyboard_shortcuts',
'context_menu', 'context_menu',

View File

@ -104,7 +104,7 @@ class DatabaseView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'nodes': [ 'nodes': [
{'get': 'node'}, {'get': 'node'},
@ -222,6 +222,15 @@ class DatabaseView(PGChildNodeView):
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
for row in res['rows']:
if self.manager.db == row['name']:
connected = True
row['canDrop'] = False
else:
conn = self.manager.connection(row['name'], did=row['did'])
connected = conn.connected()
row['canDrop'] = True
return ajax_response( return ajax_response(
response=res['rows'], response=res['rows'],
status=200 status=200
@ -733,44 +742,54 @@ class DatabaseView(PGChildNodeView):
) )
@check_precondition(action="drop") @check_precondition(action="drop")
def delete(self, gid, sid, did): def delete(self, gid, sid, did=None):
"""Delete the database.""" """Delete the database."""
default_conn = self.manager.connection()
SQL = render_template(
"/".join([self.template_path, 'delete.sql']),
did=did, conn=self.conn
)
status, res = default_conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=res)
if res is None: if did is None:
return make_json_response( data = request.form if request.form else json.loads(
status=410, request.data, encoding='utf-8'
success=0,
errormsg=_(
'Error: Object not found.'
),
info=_(
'The specified database could not be found.\n'
)
) )
else: else:
data = {'ids': [did]}
status = self.manager.release(did=did) for did in data['ids']:
default_conn = self.manager.connection()
SQL = render_template( SQL = render_template(
"/".join([self.template_path, 'delete.sql']), "/".join([self.template_path, 'delete.sql']),
datname=res, conn=self.conn did=did, conn=self.conn
) )
status, res = default_conn.execute_scalar(SQL)
status, msg = default_conn.execute_scalar(SQL)
if not status: if not status:
# reconnect if database drop failed. return internal_server_error(errormsg=res)
conn = self.manager.connection(did=did, auto_reconnect=True)
status, errmsg = conn.connect()
return internal_server_error(errormsg=msg) if res is None:
return make_json_response(
status=410,
success=0,
errormsg=_(
'Error: Object not found.'
),
info=_(
'The specified database could not be found.\n'
)
)
else:
status = self.manager.release(did=did)
SQL = render_template(
"/".join([self.template_path, 'delete.sql']),
datname=res, conn=self.conn
)
status, msg = default_conn.execute_scalar(SQL)
if not status:
# reconnect if database drop failed.
conn = self.manager.connection(did=did,
auto_reconnect=True)
status, errmsg = conn.connect()
return internal_server_error(errormsg=msg)
return make_json_response(success=1) return make_json_response(success=1)

View File

@ -164,12 +164,12 @@ class CastView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'children': [{ 'children': [{
'get': 'children' 'get': 'children'
}], }],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
'msql': [{'get': 'msql'}, {'get': 'msql'}], 'msql': [{'get': 'msql'}, {'get': 'msql'}],
@ -443,7 +443,7 @@ class CastView(PGChildNodeView):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, cid): def delete(self, gid, sid, did, cid=None):
""" """
This function will drop the cast object This function will drop the cast object
:param cid: cast id :param cid: cast id
@ -459,50 +459,54 @@ class CastView(PGChildNodeView):
else: else:
cascade = False cascade = False
try: if cid is None:
# Get name for cast from cid data = request.form if request.form else json.loads(
sql = render_template("/".join([self.template_path, 'delete.sql']), request.data, encoding='utf-8'
cid=cid)
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
if not res['rows']:
return make_json_response(
status=410,
success=0,
errormsg=gettext(
'Error: Object not found.'
),
info=gettext(
'The specified cast object could not be found.\n'
)
)
# drop cast
result = res['rows'][0]
sql = render_template("/".join([self.template_path, 'delete.sql']),
castsource=result['castsource'],
casttarget=result['casttarget'],
cascade=cascade
)
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
return make_json_response(
success=1,
info=gettext("Cast dropped"),
data={
'id': cid,
'sid': sid,
'gid': gid,
'did': did
}
) )
else:
data = {'ids': [cid]}
except Exception as e: for cid in data['ids']:
return internal_server_error(errormsg=str(e)) try:
# Get name for cast from cid
sql = render_template("/".join([self.template_path,
'delete.sql']),
cid=cid)
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
if not res['rows']:
return make_json_response(
status=410,
success=0,
errormsg=gettext(
'Error: Object not found.'
),
info=gettext(
'The specified cast object could not be found.\n'
)
)
# drop cast
result = res['rows'][0]
sql = render_template("/".join([self.template_path,
'delete.sql']),
castsource=result['castsource'],
casttarget=result['casttarget'],
cascade=cascade
)
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
except Exception as e:
return internal_server_error(errormsg=str(e))
return make_json_response(
success=1,
info=gettext("Cast dropped")
)
@check_precondition @check_precondition
def msql(self, gid, sid, did, cid=None): def msql(self, gid, sid, did, cid=None):

View File

@ -58,6 +58,7 @@ define('pgadmin.node.cast', [
// Define the backform model for cast node // Define the backform model for cast node
model: pgAdmin.Browser.Node.Model.extend({ model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, // Name of the cast name: undefined, // Name of the cast
encoding: 'UTF8', encoding: 'UTF8',

View File

@ -13,6 +13,7 @@
{% else %} {% else %}
SELECT SELECT
ca.oid, ca.oid,
ca.oid as id,
CASE CASE
WHEN {{datlastsysoid}}::OID > ca.oid then True ELSE False WHEN {{datlastsysoid}}::OID > ca.oid then True ELSE False
END AS syscast, END AS syscast,
@ -56,4 +57,4 @@
ca.oid > {{datlastsysoid}}::OID ca.oid > {{datlastsysoid}}::OID
{% endif %} {% endif %}
ORDER BY st.typname, tt.typname ORDER BY st.typname, tt.typname
{% endif %} {% endif %}

View File

@ -0,0 +1,73 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import print_function
import json
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 . import utils as cast_utils
class CastsMultipleDeleteTestCase(BaseTestGenerator):
""" This class will delete the cast node added under database node. """
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for cast node.
('Check Cast Node', dict(url='/browser/cast/obj/'))
]
def setUp(self):
super(CastsMultipleDeleteTestCase, self).setUp()
self.default_db = self.server["db"]
self.database_info = parent_node_dict['database'][-1]
self.db_name = self.database_info['db_name']
self.server["db"] = self.db_name
self.source_type = 'money'
self.target_type = 'bigint'
self.cast_id = cast_utils.create_cast(self.server, self.source_type,
self.target_type)
def runTest(self):
""" This function will delete added cast."""
self.server_id = self.database_info["server_id"]
self.db_id = self.database_info['db_id']
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
self.server_id,
self.db_id)
if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to database.")
connection = utils.get_db_connection(self.server['db'],
self.server['username'],
self.server['db_password'],
self.server['host'],
self.server['port'],
self.server['sslmode'])
response = cast_utils.verify_cast(connection, self.source_type,
self.target_type)
if len(response) == 0:
raise Exception("Could not find cast.")
delete_response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' + str(self.db_id) +
'/',
data=json.dumps({'ids': [self.cast_id]}),
content_type='html/json',
follow_redirects=True)
self.assertEquals(delete_response.status_code, 200)
def tearDown(self):
"""This function will disconnect test database."""
database_utils.disconnect_database(self, self.server_id,
self.db_id)
self.server['db'] = self.default_db

View File

@ -164,7 +164,7 @@ class EventTriggerView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
@ -478,7 +478,7 @@ class EventTriggerView(PGChildNodeView):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, etid): def delete(self, gid, sid, did, etid=None):
""" """
This function will delete an existing event trigger object. This function will delete an existing event trigger object.
@ -497,48 +497,51 @@ class EventTriggerView(PGChildNodeView):
cascade = True cascade = True
else: else:
cascade = False cascade = False
if etid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [etid]}
try: try:
sql = render_template( for etid in data['ids']:
"/".join([self.template_path, 'delete.sql']), sql = render_template(
etid=etid "/".join([self.template_path, 'delete.sql']),
) etid=etid
status, name = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=name)
if name is None:
return make_json_response(
status=410,
success=0,
errormsg=gettext(
'Error: Object not found.'
),
info=gettext(
'The specified event trigger could not be found.\n'
)
) )
status, name = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=name)
sql = render_template( if name is None:
"/".join([self.template_path, 'delete.sql']), return make_json_response(
name=name, cascade=cascade status=410,
) success=0,
status, res = self.conn.execute_scalar(sql) errormsg=gettext(
if not status: 'Error: Object not found.'
return internal_server_error(errormsg=res) ),
info=gettext(
'The specified event trigger could not be found.\n'
)
)
sql = render_template(
"/".join([self.template_path, 'delete.sql']),
name=name, cascade=cascade
)
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("Event trigger dropped"), info=gettext("Event trigger dropped")
data={
'id': etid,
'sid': sid,
'gid': gid,
'did': did
}
) )
except Exception as e: except Exception as e:
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def msql(self, gid, sid, did, etid=None): def msql(self, gid, sid, did, etid=None):

View File

@ -12,6 +12,8 @@ define('pgadmin.node.event_trigger', [
label: gettext('Event Trigger'), label: gettext('Event Trigger'),
type: 'coll-event_trigger', type: 'coll-event_trigger',
columns: ['name', 'eventowner', 'comment'], columns: ['name', 'eventowner', 'comment'],
canDrop: true,
canDropCascade: false,
}); });
} }
@ -55,6 +57,7 @@ define('pgadmin.node.event_trigger', [
}, },
// Define the model for event trigger node // Define the model for event trigger node
model: pgAdmin.Browser.Node.Model.extend({ model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
oid: undefined, oid: undefined,
name: undefined, name: undefined,

View File

@ -0,0 +1,107 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, 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 import server_utils as server_utils
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression import trigger_funcs_utils
from regression.python_test_utils import test_utils as utils
from . import utils as event_trigger_utils
class EventTriggerMultipleDeleteTestCase(BaseTestGenerator):
""" This class will delete added event trigger under test database. """
scenarios = [
# Fetching default URL for event trigger node.
('Fetch Event Trigger Node URL',
dict(url='/browser/event_trigger/obj/'))
]
def setUp(self):
self.schema_data = parent_node_dict['schema'][-1]
self.server_id = self.schema_data['server_id']
self.db_id = self.schema_data['db_id']
self.schema_name = self.schema_data['schema_name']
self.schema_id = self.schema_data['schema_id']
self.extension_name = "postgres_fdw"
self.db_name = parent_node_dict["database"][-1]["db_name"]
self.db_user = self.server["username"]
self.func_name = "trigger_func_%s" % str(uuid.uuid4())[1:8]
self.trigger_names = ["event_trigger_delete_%s" % (
str(uuid.uuid4())[1:8]), "event_trigger_delete_%s" % (
str(uuid.uuid4())[1:8])]
server_con = server_utils.connect_server(self, self.server_id)
if not server_con["info"] == "Server connected.":
raise Exception("Could not connect to server to add resource "
"groups.")
server_version = 0
if "type" in server_con["data"]:
if server_con["data"]["version"] < 90300:
message = "Event triggers are not supported by PG9.2 " \
"and PPAS9.2 and below."
self.skipTest(message)
self.function_info = trigger_funcs_utils.create_trigger_function(
self.server, self.db_name, self.schema_name, self.func_name,
server_version)
self.event_trigger_ids = []
self.event_trigger_ids.append(event_trigger_utils.create_event_trigger(
self.server, self.db_name, self.schema_name, self.func_name,
self.trigger_names[0]))
self.event_trigger_ids.append(event_trigger_utils.create_event_trigger(
self.server, self.db_name, self.schema_name, self.func_name,
self.trigger_names[1]))
def runTest(self):
""" This function will delete event trigger under test database. """
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.")
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.")
func_name = self.function_info[1]
func_response = trigger_funcs_utils.verify_trigger_function(
self.server,
self.db_name,
func_name)
if not func_response:
raise Exception("Could not find the trigger function.")
trigger_response = event_trigger_utils.verify_event_trigger(
self.server, self.db_name,
self.trigger_names[0])
if not trigger_response:
raise Exception("Could not find event trigger.")
trigger_response = event_trigger_utils.verify_event_trigger(
self.server, self.db_name,
self.trigger_names[1])
if not trigger_response:
raise Exception("Could not find event trigger.")
data = {'ids': self.event_trigger_ids}
del_response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id),
follow_redirects=True,
data=json.dumps(data),
content_type='html/json')
self.assertEquals(del_response.status_code, 200)
def tearDown(self):
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)

View File

@ -123,9 +123,9 @@ class ExtensionView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
'msql': [{'get': 'msql'}, {'get': 'msql'}], 'msql': [{'get': 'msql'}, {'get': 'msql'}],
@ -327,49 +327,53 @@ class ExtensionView(PGChildNodeView):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, eid): def delete(self, gid, sid, did, eid=None):
""" """
This function will drop/drop cascade a extension object This function will drop/drop cascade a extension object
""" """
if eid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [eid]}
cascade = True if self.cmd == 'delete' else False cascade = True if self.cmd == 'delete' else False
try: try:
# check if extension with eid exists for eid in data['ids']:
SQL = render_template("/".join( # check if extension with eid exists
[self.template_path, 'delete.sql']), eid=eid) SQL = render_template("/".join(
status, name = self.conn.execute_scalar(SQL) [self.template_path, 'delete.sql']), eid=eid)
if not status: status, name = self.conn.execute_scalar(SQL)
return internal_server_error(errormsg=name) if not status:
return internal_server_error(errormsg=name)
if name is None: if name is None:
return make_json_response( return make_json_response(
status=410, status=410,
success=0, success=0,
errormsg=gettext( errormsg=gettext(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=gettext( info=gettext(
'The specified extension could not be found.\n' 'The specified extension could not be found.\n'
)
) )
)
# drop extension # drop extension
SQL = render_template("/".join( SQL = render_template("/".join(
[self.template_path, 'delete.sql'] [self.template_path, 'delete.sql']
), name=name, cascade=cascade) ), name=name, cascade=cascade)
status, res = self.conn.execute_scalar(SQL) status, res = self.conn.execute_scalar(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("Extension dropped"), info=gettext("Extension dropped")
data={
'id': did,
'sid': sid,
'gid': gid,
}
) )
except Exception as e: except Exception as e:
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))

View File

@ -84,6 +84,7 @@ define('pgadmin.node.extension', [
* of the model in schema. * of the model in schema.
*/ */
model: pgAdmin.Browser.Node.Model.extend({ model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'eid',
schema: [ schema: [
{ {
id: 'name', label: gettext('Name'), first_empty: true, id: 'name', label: gettext('Name'), first_empty: true,

View File

@ -0,0 +1,74 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import print_function
import json
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 . import utils as extension_utils
class ExtensionsDeleteMultipleTestCase(BaseTestGenerator):
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for extension node.
('Check Extension Node', dict(url='/browser/extension/obj/'))
]
def setUp(self):
""" This function will create extensions."""
super(ExtensionsDeleteMultipleTestCase, self).setUp()
self.schema_data = parent_node_dict['schema'][-1]
self.server_id = self.schema_data['server_id']
self.db_id = self.schema_data['db_id']
self.schema_name = self.schema_data['schema_name']
self.extension_names = ["dblink", "hstore"]
self.db_name = parent_node_dict["database"][-1]["db_name"]
self.extension_ids = []
self.extension_ids.append(extension_utils.create_extension(
self.server, self.db_name, self.extension_names[0],
self.schema_name))
self.extension_ids.append(extension_utils.create_extension(
self.server, self.db_name, self.extension_names[1],
self.schema_name))
def runTest(self):
""" This function will delete extensions added test database. """
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
self.server_id,
self.db_id)
if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to database.")
response = extension_utils.verify_extension(self.server, self.db_name,
self.extension_names[0])
if not response:
raise Exception("Could not find extension.")
response = extension_utils.verify_extension(self.server, self.db_name,
self.extension_names[1])
if not response:
raise Exception("Could not find extension.")
data = {'ids': self.extension_ids}
delete_response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' + str(self.db_id),
follow_redirects=True,
data=json.dumps(data),
content_type='html/json'
)
self.assertEquals(delete_response.status_code, 200)
def tearDown(self):
"""This function disconnect the test database. """
database_utils.disconnect_database(self, self.server_id, self.db_id)

View File

@ -186,11 +186,9 @@ class ForeignDataWrapperView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{ 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'delete': 'delete'
}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -478,7 +476,7 @@ class ForeignDataWrapperView(PGChildNodeView):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, fid): def delete(self, gid, sid, did, fid=None):
""" """
This function will delete the selected foreign data wrapper node. This function will delete the selected foreign data wrapper node.
@ -488,56 +486,59 @@ class ForeignDataWrapperView(PGChildNodeView):
did: Database ID did: Database ID
fid: foreign data wrapper ID fid: foreign data wrapper ID
""" """
if fid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [fid]}
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
cascade = True cascade = True
else: else:
cascade = False cascade = False
try: for fid in data['ids']:
# Get name of foreign data wrapper from fid try:
sql = render_template("/".join([self.template_path, 'delete.sql']), # Get name of foreign data wrapper from fid
fid=fid, conn=self.conn sql = render_template("/".join([self.template_path,
) 'delete.sql']),
status, name = self.conn.execute_scalar(sql) fid=fid, conn=self.conn
if not status: )
return internal_server_error(errormsg=name) status, name = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=name)
if name is None: if name is None:
return make_json_response( return make_json_response(
status=410, status=410,
success=0, success=0,
errormsg=gettext( errormsg=gettext(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=gettext( info=gettext(
'The specified foreign data' 'The specified foreign data'
' wrapper could not be found.\n' ' wrapper could not be found.\n'
)
) )
) # drop foreign data wrapper node
# drop foreign data wrapper node sql = render_template("/".join([self.template_path,
sql = render_template("/".join([self.template_path, 'delete.sql']),
'delete.sql']), name=name,
name=name, cascade=cascade,
cascade=cascade, conn=self.conn)
conn=self.conn) status, res = self.conn.execute_scalar(sql)
status, res = self.conn.execute_scalar(sql) if not status:
if not status: return internal_server_error(errormsg=res)
return internal_server_error(errormsg=res)
return make_json_response( except Exception as e:
success=1, return internal_server_error(errormsg=str(e))
info=gettext("Foreign Data Wrapper dropped"),
data={
'id': fid,
'did': did,
'sid': sid,
'gid': gid,
}
)
except Exception as e: return make_json_response(
return internal_server_error(errormsg=str(e)) success=1,
info=gettext("Foreign Data Wrapper dropped")
)
@check_precondition @check_precondition
def msql(self, gid, sid, did, fid=None): def msql(self, gid, sid, did, fid=None):

View File

@ -183,11 +183,9 @@ class ForeignServerView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{ 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'delete': 'delete'
}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -498,7 +496,7 @@ class ForeignServerView(PGChildNodeView):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, fid, fsid): def delete(self, gid, sid, did, fid, fsid=None):
""" """
This function will delete the selected foreign server node. This function will delete the selected foreign server node.
@ -510,6 +508,13 @@ class ForeignServerView(PGChildNodeView):
fsid: foreign server ID fsid: foreign server ID
""" """
if fsid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [fsid]}
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
cascade = True cascade = True
@ -517,43 +522,40 @@ class ForeignServerView(PGChildNodeView):
cascade = False cascade = False
try: try:
# Get name of foreign data wrapper from fid for fsid in data['ids']:
sql = render_template("/".join([self.template_path, 'delete.sql']), # Get name of foreign data wrapper from fid
fsid=fsid, conn=self.conn) sql = render_template("/".join([self.template_path,
status, name = self.conn.execute_scalar(sql) 'delete.sql']),
if not status: fsid=fsid, conn=self.conn)
return internal_server_error(errormsg=name) status, name = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=name)
if name is None: if name is None:
return make_json_response( return make_json_response(
status=410, status=410,
success=0, success=0,
errormsg=gettext( errormsg=gettext(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=gettext( info=gettext(
'The specified foreign server could not be found.\n' 'The specified foreign server '
'could not be found.\n'
)
) )
)
# drop foreign server # drop foreign server
sql = render_template("/".join([self.template_path, 'delete.sql']), sql = render_template("/".join([self.template_path,
name=name, cascade=cascade, 'delete.sql']),
conn=self.conn) name=name, cascade=cascade,
status, res = self.conn.execute_scalar(sql) conn=self.conn)
if not status: status, res = self.conn.execute_scalar(sql)
return internal_server_error(errormsg=res) if not status:
return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("Foreign Server dropped"), info=gettext("Foreign Server dropped")
data={
'id': fsid,
'fid': fid,
'did': did,
'sid': sid,
'gid': gid,
}
) )
except Exception as e: except Exception as e:

View File

@ -92,6 +92,7 @@ define('pgadmin.node.foreign_server', [
// Defining model for foreign server node // Defining model for foreign server node
model: pgAdmin.Browser.Node.Model.extend({ model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'fsrvid',
defaults: { defaults: {
name: undefined, name: undefined,
fsrvtype: undefined, fsrvtype: undefined,

View File

@ -11,8 +11,6 @@ from __future__ import print_function
import uuid import uuid
from pgadmin.browser.server_groups.servers.databases.extensions.tests import \
utils as extension_utils
from pgadmin.browser.server_groups.servers.databases.foreign_data_wrappers.\ from pgadmin.browser.server_groups.servers.databases.foreign_data_wrappers.\
tests import utils as fdw_utils tests import utils as fdw_utils
from pgadmin.browser.server_groups.servers.databases.tests import \ from pgadmin.browser.server_groups.servers.databases.tests import \
@ -39,11 +37,9 @@ class ForeignServerDeleteTestCase(BaseTestGenerator):
self.db_id = self.schema_data['db_id'] self.db_id = self.schema_data['db_id']
self.db_name = parent_node_dict["database"][-1]["db_name"] self.db_name = parent_node_dict["database"][-1]["db_name"]
self.schema_name = self.schema_data['schema_name'] self.schema_name = self.schema_data['schema_name']
self.extension_name = "cube"
self.fdw_name = "test_fdw_%s" % (str(uuid.uuid4())[1:8]) self.fdw_name = "test_fdw_%s" % (str(uuid.uuid4())[1:8])
self.fsrv_name = "test_fsrv_%s" % (str(uuid.uuid4())[1:8]) self.fsrv_name = "test_fsrv_%s" % (str(uuid.uuid4())[1:8])
self.extension_id = extension_utils.create_extension(
self.server, self.db_name, self.extension_name, self.schema_name)
self.fdw_id = fdw_utils.create_fdw(self.server, self.db_name, self.fdw_id = fdw_utils.create_fdw(self.server, self.db_name,
self.fdw_name) self.fdw_name)
self.fsrv_id = fsrv_utils.create_fsrv(self.server, self.db_name, self.fsrv_id = fsrv_utils.create_fsrv(self.server, self.db_name,
@ -75,8 +71,9 @@ class ForeignServerDeleteTestCase(BaseTestGenerator):
self.assertEquals(delete_response.status_code, 200) self.assertEquals(delete_response.status_code, 200)
def tearDown(self): def tearDown(self):
"""This function disconnect the test database and drop added extension """This function disconnect the test database and drop
and dependant objects.""" added foreign data server and dependant objects."""
extension_utils.drop_extension(self.server, self.db_name, fdw_utils.delete_fdw(self.server, self.db_name,
self.extension_name) self.fdw_name)
database_utils.disconnect_database(self, self.server_id, self.db_id) database_utils.disconnect_database(self, self.server_id,
self.db_id)

View File

@ -0,0 +1,90 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import print_function
import uuid
import json
from pgadmin.browser.server_groups.servers.databases.foreign_data_wrappers.\
tests import utils as fdw_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 . import utils as fsrv_utils
class ForeignServerDeleteMultipleTestCase(BaseTestGenerator):
"""This class will add foreign server under FDW node."""
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for foreign server node.
('Check FSRV Node', dict(url='/browser/foreign_server/obj/'))
]
def setUp(self):
""" This function will create extension and foreign data wrapper."""
super(ForeignServerDeleteMultipleTestCase, self).setUp()
self.schema_data = parent_node_dict['schema'][-1]
self.server_id = self.schema_data['server_id']
self.db_id = self.schema_data['db_id']
self.db_name = parent_node_dict["database"][-1]["db_name"]
self.schema_name = self.schema_data['schema_name']
self.fdw_name = "test_fdw_%s" % (str(uuid.uuid4())[1:8])
self.fsrv_names = ["test_fsrv_%s" % (str(uuid.uuid4())[1:8]),
"test_fsrv_%s" % (str(uuid.uuid4())[1:8])]
self.fdw_id = fdw_utils.create_fdw(self.server, self.db_name,
self.fdw_name)
self.fsrv_ids = [fsrv_utils.create_fsrv(self.server, self.db_name,
self.fsrv_names[0],
self.fdw_name),
fsrv_utils.create_fsrv(self.server, self.db_name,
self.fsrv_names[1],
self.fdw_name)]
def runTest(self):
"""This function will fetch foreign server present under test
database."""
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
self.server_id,
self.db_id)
if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to database.")
fdw_response = fdw_utils.verify_fdw(self.server, self.db_name,
self.fdw_name)
if not fdw_response:
raise Exception("Could not find FDW.")
fsrv_response = fsrv_utils.verify_fsrv(self.server, self.db_name,
self.fsrv_names[0])
if not fsrv_response:
raise Exception("Could not find FSRV.")
fsrv_response = fsrv_utils.verify_fsrv(self.server, self.db_name,
self.fsrv_names[1])
if not fsrv_response:
raise Exception("Could not find FSRV.")
data = {'ids': self.fsrv_ids}
delete_response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' + str(self.db_id) +
'/' + str(self.fdw_id) + "/",
data=json.dumps(data),
content_type='html/json',
follow_redirects=True)
self.assertEquals(delete_response.status_code, 200)
def tearDown(self):
"""This function disconnect the test database and drop added
foreign data server and dependant objects."""
fdw_utils.delete_fdw(self.server, self.db_name,
self.fdw_name)
database_utils.disconnect_database(self, self.server_id, self.db_id)

View File

@ -200,11 +200,9 @@ class UserMappingView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{ 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'delete': 'delete'
}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -506,7 +504,7 @@ class UserMappingView(PGChildNodeView):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, fid, fsid, umid): def delete(self, gid, sid, did, fid, fsid, umid=None):
""" """
This function will delete the selected user mapping node. This function will delete the selected user mapping node.
@ -518,6 +516,12 @@ class UserMappingView(PGChildNodeView):
fsid: foreign server ID fsid: foreign server ID
umid: User mapping ID umid: User mapping ID
""" """
if umid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [umid]}
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
@ -526,64 +530,59 @@ class UserMappingView(PGChildNodeView):
cascade = False cascade = False
try: try:
# Get name of foreign server from fsid for umid in data['ids']:
sql = render_template("/".join([self.template_path, 'delete.sql']), # Get name of foreign server from fsid
fsid=fsid, conn=self.conn) sql = render_template("/".join([self.template_path,
status, name = self.conn.execute_scalar(sql) 'delete.sql']),
if not status: fsid=fsid, conn=self.conn)
return internal_server_error(errormsg=name) status, name = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=name)
if name is None: if name is None:
return make_json_response( return make_json_response(
status=410, status=410,
success=0, success=0,
errormsg=gettext( errormsg=gettext(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=gettext( info=gettext(
'The specified foreign server could not be found.\n' 'The specified foreign server '
'could not be found.\n'
)
) )
)
sql = render_template("/".join([self.template_path, sql = render_template("/".join([self.template_path,
'properties.sql']), 'properties.sql']),
umid=umid, conn=self.conn) umid=umid, conn=self.conn)
status, res = self.conn.execute_dict(sql) status, res = self.conn.execute_dict(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
if not res['rows']: if not res['rows']:
return make_json_response( return make_json_response(
status=410, status=410,
success=0, success=0,
errormsg=gettext( errormsg=gettext(
'The specified user mapping could not be found.\n' 'The specified user mapping could not be found.\n'
)
) )
)
data = res['rows'][0] data = res['rows'][0]
# drop user mapping # drop user mapping
sql = render_template("/".join([self.template_path, 'delete.sql']), sql = render_template("/".join([self.template_path,
data=data, name=name, cascade=cascade, 'delete.sql']),
conn=self.conn) data=data, name=name, cascade=cascade,
status, res = self.conn.execute_scalar(sql) conn=self.conn)
if not status: status, res = self.conn.execute_scalar(sql)
return internal_server_error(errormsg=res) if not status:
return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("User Mapping dropped"), info=gettext("User Mapping dropped")
data={
'id': umid,
'fsid': fsid,
'fid': fid,
'did': did,
'sid': sid,
'gid': gid,
}
) )
except Exception as e: except Exception as e:
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))

View File

@ -96,6 +96,7 @@ define('pgadmin.node.user_mapping', [
// Defining model for user mapping node // Defining model for user mapping node
model: pgAdmin.Browser.Node.Model.extend({ model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'um_oid',
defaults: { defaults: {
name: undefined, name: undefined,
um_options: [], um_options: [],

View File

@ -41,11 +41,8 @@ class UserMappingDeleteTestCase(BaseTestGenerator):
self.db_id = self.schema_data['db_id'] self.db_id = self.schema_data['db_id']
self.db_name = parent_node_dict["database"][-1]["db_name"] self.db_name = parent_node_dict["database"][-1]["db_name"]
self.schema_name = self.schema_data['schema_name'] self.schema_name = self.schema_data['schema_name']
self.extension_name = "cube"
self.fdw_name = "fdw_%s" % (str(uuid.uuid4())[1:8]) self.fdw_name = "fdw_%s" % (str(uuid.uuid4())[1:8])
self.fsrv_name = "fsrv_%s" % (str(uuid.uuid4())[1:8]) self.fsrv_name = "fsrv_%s" % (str(uuid.uuid4())[1:8])
self.extension_id = extension_utils.create_extension(
self.server, self.db_name, self.extension_name, self.schema_name)
self.fdw_id = fdw_utils.create_fdw(self.server, self.db_name, self.fdw_id = fdw_utils.create_fdw(self.server, self.db_name,
self.fdw_name) self.fdw_name)
self.fsrv_id = fsrv_utils.create_fsrv(self.server, self.db_name, self.fsrv_id = fsrv_utils.create_fsrv(self.server, self.db_name,
@ -83,8 +80,9 @@ class UserMappingDeleteTestCase(BaseTestGenerator):
self.assertEquals(delete_response.status_code, 200) self.assertEquals(delete_response.status_code, 200)
def tearDown(self): def tearDown(self):
"""This function disconnect the test database and drop added extension """This function disconnect the test database and drop
and dependant objects.""" foreign data wrapper and dependant objects."""
extension_utils.drop_extension(self.server, self.db_name, fdw_utils.delete_fdw(self.server, self.db_name,
self.extension_name) self.fdw_name)
database_utils.disconnect_database(self, self.server_id, self.db_id) database_utils.disconnect_database(self, self.server_id,
self.db_id)

View File

@ -0,0 +1,91 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import print_function
import uuid
import json
from pgadmin.browser.server_groups.servers.databases.extensions.tests import \
utils as extension_utils
from pgadmin.browser.server_groups.servers.databases.foreign_data_wrappers. \
foreign_servers.tests import utils as fsrv_utils
from pgadmin.browser.server_groups.servers.databases.foreign_data_wrappers.\
tests import utils as fdw_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 . import utils as um_utils
class UserMappingDeleteMultipleTestCase(BaseTestGenerator):
"""This class will delete user mapping under foreign server node."""
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for user mapping node.
('Check user mapping Node', dict(url='/browser/user_mapping/obj/'))
]
def setUp(self):
""" This function will create extension and foreign data wrapper."""
super(UserMappingDeleteMultipleTestCase, self).setUp()
self.schema_data = parent_node_dict['schema'][-1]
self.server_id = self.schema_data['server_id']
self.db_id = self.schema_data['db_id']
self.db_name = parent_node_dict["database"][-1]["db_name"]
self.schema_name = self.schema_data['schema_name']
self.fdw_name = "fdw_%s" % (str(uuid.uuid4())[1:8])
self.fsrv_name = "fsrv_%s" % (str(uuid.uuid4())[1:8])
self.fdw_id = fdw_utils.create_fdw(self.server, self.db_name,
self.fdw_name)
self.fsrv_id = fsrv_utils.create_fsrv(self.server, self.db_name,
self.fsrv_name, self.fdw_name)
self.um_id = um_utils.create_user_mapping(self.server, self.db_name,
self.fsrv_name)
def runTest(self):
"""This function will delete user mapping present under test
database. """
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
self.server_id,
self.db_id)
if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to database.")
fdw_response = fdw_utils.verify_fdw(self.server, self.db_name,
self.fdw_name)
if not fdw_response:
raise Exception("Could not find FDW.")
fsrv_response = fsrv_utils.verify_fsrv(self.server, self.db_name,
self.fsrv_name)
if not fsrv_response:
raise Exception("Could not find FSRV.")
um_response = um_utils.verify_user_mapping(self.server, self.db_name,
self.fsrv_name)
if not um_response:
raise Exception("Could not find user mapping.")
data = {'ids': [self.um_id]}
delete_response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' + str(self.db_id) +
'/' + str(self.fdw_id) + '/' +
str(self.fsrv_id) + "/",
follow_redirects=True,
data=json.dumps(data),
content_type='html/json')
self.assertEquals(delete_response.status_code, 200)
def tearDown(self):
"""This function disconnect the test database and drop
foreign data wrapper and dependant objects."""
fdw_utils.delete_fdw(self.server, self.db_name, self.fdw_name)
database_utils.disconnect_database(self, self.server_id,
self.db_id)

View File

@ -95,6 +95,7 @@ define('pgadmin.node.foreign_data_wrapper', [
// Defining model for foreign data wrapper node // Defining model for foreign data wrapper node
model: pgBrowser.Node.Model.extend({ model: pgBrowser.Node.Model.extend({
idAttribute: 'fdwoid',
defaults: { defaults: {
name: undefined, name: undefined,
fdwowner: undefined, fdwowner: undefined,

View File

@ -0,0 +1,76 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import print_function
import uuid
import json
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 . import utils as fdw_utils
class FDWDDeleteMultipleTestCase(BaseTestGenerator):
"""This class will delete foreign data wrappers under test database."""
skip_on_database = ['gpdb']
scenarios = [ # Fetching default URL for foreign_data_wrapper node.
('Check FDW Node',
dict(url='/browser/foreign_data_wrapper/obj/'))]
def setUp(self):
""" This function will create extension and foreign data wrapper."""
super(FDWDDeleteMultipleTestCase, self).setUp()
self.schema_data = parent_node_dict['schema'][-1]
self.server_id = self.schema_data['server_id']
self.db_id = self.schema_data['db_id']
self.db_name = parent_node_dict["database"][-1]["db_name"]
self.schema_name = self.schema_data['schema_name']
self.fdw_names = ["fdw_{0}".format(str(uuid.uuid4())[1:8]),
"fdw_{0}".format(str(uuid.uuid4())[1:8])]
self.fdw_ids = [fdw_utils.create_fdw(self.server, self.db_name,
self.fdw_names[0]),
fdw_utils.create_fdw(self.server, self.db_name,
self.fdw_names[1])]
def runTest(self):
"""This function will fetch foreign data wrapper present under test
database."""
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
self.server_id,
self.db_id)
if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to database.")
fdw_response = fdw_utils.verify_fdw(self.server, self.db_name,
self.fdw_names[0])
if not fdw_response:
raise Exception("Could not find FDW.")
fdw_response = fdw_utils.verify_fdw(self.server, self.db_name,
self.fdw_names[1])
if not fdw_response:
raise Exception("Could not find FDW.")
data = {'ids': self.fdw_ids}
delete_response = self.tester.delete(self.url +
str(utils.SERVER_GROUP) +
'/' + str(self.server_id) + '/' +
str(self.db_id) + '/',
follow_redirects=True,
data=json.dumps(data),
content_type='html/json')
self.assertEquals(delete_response.status_code, 200)
def tearDown(self):
"""This function disconnect the test database and drop added extension
and dependant objects."""
database_utils.disconnect_database(self, self.server_id,
self.db_id)

View File

@ -128,6 +128,6 @@ def delete_fdw(server, db_name, fdw_name):
server['port'], server['port'],
server['sslmode']) server['sslmode'])
pg_cursor = connection.cursor() pg_cursor = connection.cursor()
pg_cursor.execute("DROP FOREIGN DATA WRAPPER %s" % fdw_name) pg_cursor.execute("DROP FOREIGN DATA WRAPPER %s CASCADE" % fdw_name)
connection.commit() connection.commit()
connection.close() connection.close()

View File

@ -188,7 +188,7 @@ class LanguageView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -198,7 +198,7 @@ class LanguageView(PGChildNodeView):
'dependent': [{'get': 'dependents'}], 'dependent': [{'get': 'dependents'}],
'get_functions': [{}, {'get': 'get_functions'}], 'get_functions': [{}, {'get': 'get_functions'}],
'get_templates': [{}, {'get': 'get_templates'}], 'get_templates': [{}, {'get': 'get_templates'}],
'delete': [{'delete': 'delete'}] 'delete': [{'delete': 'delete'}, {'delete': 'delete'}]
}) })
def _init_(self, **kwargs): def _init_(self, **kwargs):
@ -490,7 +490,7 @@ class LanguageView(PGChildNodeView):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, lid): def delete(self, gid, sid, did, lid=None):
""" """
This function will drop the language object This function will drop the language object
@ -500,6 +500,13 @@ class LanguageView(PGChildNodeView):
did: Database ID did: Database ID
lid: Language ID lid: Language ID
""" """
if lid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [lid]}
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
cascade = True cascade = True
@ -507,35 +514,30 @@ class LanguageView(PGChildNodeView):
cascade = False cascade = False
try: try:
# Get name for language from lid for lid in data['ids']:
sql = render_template( # Get name for language from lid
"/".join([self.template_path, 'delete.sql']), sql = render_template(
lid=lid, conn=self.conn "/".join([self.template_path, 'delete.sql']),
) lid=lid, conn=self.conn
status, lname = self.conn.execute_scalar(sql) )
status, lname = self.conn.execute_scalar(sql)
if not status: if not status:
return internal_server_error(errormsg=lname) return internal_server_error(errormsg=lname)
# drop language # drop language
sql = render_template( sql = render_template(
"/".join([self.template_path, 'delete.sql']), "/".join([self.template_path, 'delete.sql']),
lname=lname, cascade=cascade, conn=self.conn lname=lname, cascade=cascade, conn=self.conn
) )
status, res = self.conn.execute_scalar(sql) status, res = self.conn.execute_scalar(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("Language dropped"), info=gettext("Language dropped")
data={
'id': lid,
'did': did,
'sid': sid,
'gid': gid,
}
) )
except Exception as e: except Exception as e:

View File

@ -59,6 +59,7 @@ define('pgadmin.node.language', [
// Define the model for language node // Define the model for language node
model: pgBrowser.Node.Model.extend({ model: pgBrowser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, name: undefined,
lanowner: undefined, lanowner: undefined,

View File

@ -0,0 +1,67 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import print_function
import uuid
import json
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 . import utils as language_utils
class LanguagesDeleteMultipleTestCase(BaseTestGenerator):
scenarios = [
('Language delete test case', dict(url='/browser/language/obj/'))
]
def setUp(self):
self.server_data = parent_node_dict["database"][-1]
self.server_id = self.server_data["server_id"]
self.db_id = self.server_data['db_id']
self.db_name = self.server_data["db_name"]
self.lang_names = ["language_%s" % str(uuid.uuid4())[1:8],
"language_%s" % str(uuid.uuid4())[1:8]]
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
self.server_id,
self.db_id)
if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to database.")
self.language_ids = [language_utils.create_language(
self.server,
self.db_name,
self.lang_names[0]
),
language_utils.create_language(
self.server,
self.db_name,
self.lang_names[1])
]
def runTest(self):
"""This function will delete languages under test database."""
data = {'ids': self.language_ids}
response = self.tester.delete("{0}{1}/{2}/{3}/".format(
self.url, utils.SERVER_GROUP, self.server_id, self.db_id),
follow_redirects=True,
data=json.dumps(data),
content_type='html/json'
)
self.assertEquals(response.status_code, 200)
def tearDown(self):
"""This function disconnect the test database."""
database_utils.disconnect_database(self, self.server_id, self.db_id)

View File

@ -214,7 +214,7 @@ class SchemaView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'nodes'}, {'get': 'nodes'}], 'nodes': [{'get': 'nodes'}, {'get': 'nodes'}],
@ -223,7 +223,8 @@ class SchemaView(PGChildNodeView):
'stats': [{'get': 'statistics'}], 'stats': [{'get': 'statistics'}],
'dependency': [{'get': 'dependencies'}], 'dependency': [{'get': 'dependencies'}],
'dependent': [{'get': 'dependents'}], 'dependent': [{'get': 'dependents'}],
'delete': [{'delete': 'delete'}] 'delete': [{'delete': 'delete'},
{'delete': 'delete'}]
}) })
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -645,7 +646,7 @@ It may have been removed by another user.
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid): def delete(self, gid, sid, did, scid=None):
""" """
This function will delete an existing schema object This function will delete an existing schema object
@ -656,54 +657,56 @@ It may have been removed by another user.
scid: Schema ID scid: Schema ID
""" """
try: if scid is None:
# Get name for schema from did data = request.form if request.form else json.loads(
SQL = render_template( request.data, encoding='utf-8'
"/".join([self.template_path, 'sql/get_name.sql']),
_=gettext,
scid=scid
) )
else:
data = {'ids': [scid]}
status, name = self.conn.execute_scalar(SQL) for scid in data['ids']:
if not status: try:
return internal_server_error(errormsg=name) # Get name for schema from did
SQL = render_template(
if name is None: "/".join([self.template_path, 'sql/get_name.sql']),
return make_json_response( _=gettext,
status=410, scid=scid
success=0,
errormsg=gettext(
'Error: Object not found.'
),
info=gettext(
'The specified schema could not be found.\n'
)
) )
# drop schema status, name = self.conn.execute_scalar(SQL)
SQL = render_template( if not status:
"/".join([self.template_path, 'sql/delete.sql']), return internal_server_error(errormsg=name)
_=gettext, name=name, conn=self.conn,
cascade=True if self.cmd == 'delete' else False
)
status, res = self.conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=res)
return make_json_response( if name is None:
success=1, return make_json_response(
info=gettext("Schema dropped"), status=410,
data={ success=0,
'id': scid, errormsg=gettext(
'sid': sid, 'Error: Object not found.'
'gid': gid, ),
'did': did info=gettext(
} 'The specified schema could not be found.\n'
) )
)
except Exception as e: # drop schema
current_app.logger.exception(e) SQL = render_template(
return internal_server_error(errormsg=str(e)) "/".join([self.template_path, 'sql/delete.sql']),
_=gettext, name=name, conn=self.conn,
cascade=True if self.cmd == 'delete' else False
)
status, res = self.conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=res)
except Exception as e:
current_app.logger.exception(e)
return internal_server_error(errormsg=str(e))
return make_json_response(
success=1,
info=gettext("Schema dropped")
)
@check_precondition @check_precondition
def msql(self, gid, sid, did, scid=None): def msql(self, gid, sid, did, scid=None):

View File

@ -10,6 +10,8 @@ define('pgadmin.node.catalog_object_column', [
label: gettext('catalog_object_column'), label: gettext('catalog_object_column'),
type: 'coll-catalog_object_column', type: 'coll-catalog_object_column',
columns: ['attname', 'attnum', 'cltype', 'description'], columns: ['attname', 'attnum', 'cltype', 'description'],
canDrop: false,
canDropCascade: false,
}); });
} }

View File

@ -10,6 +10,8 @@ define('pgadmin.node.catalog_object', [
label: gettext('Catalog Objects'), label: gettext('Catalog Objects'),
type: 'coll-catalog_object', type: 'coll-catalog_object',
columns: ['name', 'owner', 'description'], columns: ['name', 'owner', 'description'],
canDrop: false,
canDropCascade: false,
}); });
} }

View File

@ -161,9 +161,9 @@ class CollationView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -482,7 +482,7 @@ class CollationView(PGChildNodeView):
) )
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, coid): def delete(self, gid, sid, did, scid, coid=None):
""" """
This function will delete existing the collation object This function will delete existing the collation object
@ -493,6 +493,12 @@ class CollationView(PGChildNodeView):
scid: Schema ID scid: Schema ID
coid: Collation ID coid: Collation ID
""" """
if coid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [coid]}
# Below will decide if it's simple drop or drop with cascade call # Below will decide if it's simple drop or drop with cascade call
if self.cmd == 'delete': if self.cmd == 'delete':
@ -502,40 +508,36 @@ class CollationView(PGChildNodeView):
cascade = False cascade = False
try: try:
SQL = render_template("/".join([self.template_path, for coid in data['ids']:
'get_name.sql']), SQL = render_template("/".join([self.template_path,
scid=scid, coid=coid) 'get_name.sql']),
status, name = self.conn.execute_scalar(SQL) scid=scid, coid=coid)
if not status: status, name = self.conn.execute_scalar(SQL)
return internal_server_error(errormsg=name) if not status:
return internal_server_error(errormsg=name)
if name is None: if name is None:
return make_json_response( return make_json_response(
success=0, success=0,
errormsg=gettext( errormsg=gettext(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=gettext( info=gettext(
'The specified collation could not be found.\n' 'The specified collation could not be found.\n'
)
) )
)
SQL = render_template("/".join([self.template_path, SQL = render_template("/".join([self.template_path,
'delete.sql']), 'delete.sql']),
name=name, cascade=cascade, name=name, cascade=cascade,
conn=self.conn) conn=self.conn)
status, res = self.conn.execute_scalar(SQL) status, res = self.conn.execute_scalar(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("Collation dropped"), info=gettext("Collation dropped")
data={
'id': coid,
'scid': scid,
'did': did
}
) )
except Exception as e: except Exception as e:

View File

@ -54,6 +54,7 @@ define('pgadmin.node.collation', [
}, },
model: pgAdmin.Browser.Node.Model.extend({ model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, name: undefined,
oid: undefined, oid: undefined,

View File

@ -0,0 +1,80 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, 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 . import utils as collation_utils
class CollationDeleteMultipleTestCase(BaseTestGenerator):
""" This class will delete added collations under schema node. """
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for collation node.
('Fetch collation Node URL', dict(url='/browser/collation/obj/'))
]
def setUp(self):
super(CollationDeleteMultipleTestCase, self).setUp()
self.schema_info = parent_node_dict["schema"][-1]
self.schema_name = self.schema_info["schema_name"]
self.db_name = parent_node_dict["database"][-1]["db_name"]
coll_names = ["collation_get_%s" % str(uuid.uuid4())[1:8],
"collation_get_%s" % str(uuid.uuid4())[1:8]]
self.collations = [collation_utils.create_collation(self.server,
self.schema_name,
coll_names[0],
self.db_name),
collation_utils.create_collation(self.server,
self.schema_name,
coll_names[1],
self.db_name)
]
def runTest(self):
""" This function will delete collations under schema node. """
server_id = self.schema_info["server_id"]
db_id = self.schema_info["db_id"]
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
server_id,
db_id)
if not db_con['data']["connected"]:
raise Exception("Could not connect to database.")
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.")
data = {'ids': [self.collations[0][0], self.collations[1][0]]}
schema_id = self.schema_info["schema_id"]
get_response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' + str(
server_id) + '/' +
str(db_id) + '/' + str(schema_id),
content_type='html/json',
data=json.dumps(data),
follow_redirects=True,
)
self.assertEquals(get_response.status_code, 200)
# Disconnect database to delete it
database_utils.disconnect_database(self, server_id, db_id)
def tearDown(self):
pass

View File

@ -158,9 +158,9 @@ class DomainView(PGChildNodeView, DataTypeReader):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -581,7 +581,7 @@ AND relkind != 'c'))"""
) )
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, doid): def delete(self, gid, sid, did, scid, doid=None):
""" """
Drops the Domain object. Drops the Domain object.
@ -592,6 +592,12 @@ AND relkind != 'c'))"""
scid: Schema Id scid: Schema Id
doid: Domain Id doid: Domain Id
""" """
if doid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [doid]}
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
@ -599,45 +605,39 @@ AND relkind != 'c'))"""
else: else:
cascade = False cascade = False
SQL = render_template("/".join([self.template_path, for doid in data['ids']:
'delete.sql']), SQL = render_template("/".join([self.template_path,
scid=scid, doid=doid) 'delete.sql']),
status, res = self.conn.execute_2darray(SQL) scid=scid, doid=doid)
if not status: status, res = self.conn.execute_2darray(SQL)
return internal_server_error(errormsg=res) if not status:
return internal_server_error(errormsg=res)
if not res['rows']: if not res['rows']:
return make_json_response( return make_json_response(
status=410, status=410,
success=0, success=0,
errormsg=gettext( errormsg=gettext(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=gettext( info=gettext(
'The specified domain could not be found.\n' 'The specified domain could not be found.\n'
)
) )
)
name = res['rows'][0]['name'] name = res['rows'][0]['name']
basensp = res['rows'][0]['basensp'] basensp = res['rows'][0]['basensp']
SQL = render_template("/".join([self.template_path, SQL = render_template("/".join([self.template_path,
'delete.sql']), 'delete.sql']),
name=name, basensp=basensp, cascade=cascade) name=name, basensp=basensp, cascade=cascade)
status, res = self.conn.execute_scalar(SQL) status, res = self.conn.execute_scalar(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("Domain dropped"), info=gettext("Domain dropped")
data={
'id': doid,
'scid': scid,
'sid': sid,
'gid': gid,
'did': did
}
) )
@check_precondition @check_precondition

View File

@ -167,9 +167,8 @@ class DomainConstraintView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -450,7 +449,7 @@ class DomainConstraintView(PGChildNodeView):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, doid, coid): def delete(self, gid, sid, did, scid, doid, coid=None):
""" """
Drops the Domain Constraint object. Drops the Domain Constraint object.
@ -462,45 +461,47 @@ class DomainConstraintView(PGChildNodeView):
doid: Domain Id doid: Domain Id
coid: Domain Constraint Id coid: Domain Constraint Id
""" """
if coid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [coid]}
try: try:
SQL = render_template("/".join([self.template_path, for coid in data['ids']:
'properties.sql']), SQL = render_template("/".join([self.template_path,
doid=doid, coid=coid) 'properties.sql']),
status, res = self.conn.execute_dict(SQL) doid=doid, coid=coid)
status, res = self.conn.execute_dict(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
if not res['rows']: if not res['rows']:
return make_json_response( return make_json_response(
success=0, success=0,
errormsg=gettext( errormsg=gettext(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=gettext( info=gettext(
'The specified domain constraint could not be found.\n' 'The specified domain constraint '
'could not be found.\n'
)
) )
)
data = res['rows'][0] data = res['rows'][0]
SQL = render_template("/".join([self.template_path, SQL = render_template("/".join([self.template_path,
'delete.sql']), 'delete.sql']),
data=data) data=data)
status, res = self.conn.execute_scalar(SQL) status, res = self.conn.execute_scalar(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("Domain Constraint dropped"), info=gettext("Domain Constraint dropped")
data={
'id': doid,
'scid': scid,
'sid': sid,
'gid': gid,
'did': did
}
) )
except Exception as e: except Exception as e:

View File

@ -13,6 +13,8 @@ define('pgadmin.node.domain_constraints', [
label: gettext('Domain Constraints'), label: gettext('Domain Constraints'),
type: 'coll-domain_constraints', type: 'coll-domain_constraints',
columns: ['name', 'description'], columns: ['name', 'description'],
canDrop: true,
canDropCascade: false,
}); });
} }
@ -59,6 +61,7 @@ define('pgadmin.node.domain_constraints', [
}, },
canDrop: schemaChildTreeNode.isTreeItemOfChildOfSchema, canDrop: schemaChildTreeNode.isTreeItemOfChildOfSchema,
model: pgAdmin.Browser.Node.Model.extend({ model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, name: undefined,
oid: undefined, oid: undefined,

View File

@ -120,6 +120,7 @@ define('pgadmin.node.domain', [
}, },
// Domain Node Model // Domain Node Model
model: pgBrowser.Node.Model.extend({ model: pgBrowser.Node.Model.extend({
idAttribute: 'oid',
initialize: function(attrs, args) { initialize: function(attrs, args) {
var isNew = (_.size(attrs) === 0); var isNew = (_.size(attrs) === 0);
if (isNew) { if (isNew) {

View File

@ -23,7 +23,7 @@ class DomainDeleteTestCase(BaseTestGenerator):
""" This class will delete new domain under schema node. """ """ This class will delete new domain under schema node. """
scenarios = [ scenarios = [
# Fetching default URL for domain node. # Fetching default URL for domain node.
('Fetch domain Node URL', dict(url='/browser/domain/delete/')) ('Fetch domain Node URL', dict(url='/browser/domain/obj/'))
] ]
def setUp(self): def setUp(self):
@ -61,8 +61,12 @@ class DomainDeleteTestCase(BaseTestGenerator):
str(db_id) + '/' + str(db_id) + '/' +
str(self.schema_id) + '/' + str(self.schema_id) + '/' +
str(domain_id), str(domain_id),
content_type='html/json') content_type='html/json',
follow_redirects=True
)
self.assertEquals(get_response.status_code, 200) self.assertEquals(get_response.status_code, 200)
# Disconnect the database # Disconnect the database
database_utils.disconnect_database(self, server_id, db_id) database_utils.disconnect_database(self, server_id, db_id)

View File

@ -0,0 +1,79 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, 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 . import utils as domain_utils
class DomainDeleteMultipleTestCase(BaseTestGenerator):
""" This class will delete new domains under schema node. """
scenarios = [
# Fetching default URL for domain node.
('Fetch domain Node URL', dict(url='/browser/domain/obj/'))
]
def setUp(self):
super(DomainDeleteMultipleTestCase, self).setUp()
self.database_info = parent_node_dict["database"][-1]
self.db_name = self.database_info["db_name"]
self.schema_info = parent_node_dict["schema"][-1]
self.schema_name = self.schema_info["schema_name"]
self.schema_id = self.schema_info["schema_id"]
self.domain_names = ["domain_delete_%s" % (str(uuid.uuid4())[1:8]),
"domain_delete_%s" % (str(uuid.uuid4())[1:8])]
self.domain_infos = [domain_utils.create_domain(self.server,
self.db_name,
self.schema_name,
self.schema_id,
self.domain_names[0]),
domain_utils.create_domain(self.server,
self.db_name,
self.schema_name,
self.schema_id,
self.domain_names[1])]
def runTest(self):
""" This function will add domain under schema node. """
db_id = self.database_info["db_id"]
server_id = self.database_info["server_id"]
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
server_id, db_id)
if not db_con['data']["connected"]:
raise Exception("Could not connect to database to get the domain.")
db_name = self.database_info["db_name"]
schema_response = schema_utils.verify_schemas(self.server,
db_name,
self.schema_name)
if not schema_response:
raise Exception("Could not find the schema to get the domain.")
data = {'ids': [self.domain_infos[0][0], self.domain_infos[1][0]]}
url = self.url + str(utils.SERVER_GROUP) + '/' + str(
server_id) + '/' + str(db_id) + '/' + str(self.schema_id) + "/"
# Call GET API to verify the domain
get_response = self.tester.delete(
url,
content_type='html/json',
follow_redirects=True,
data=json.dumps(data))
self.assertEquals(get_response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, server_id, db_id)
def tearDown(self):
pass

View File

@ -194,9 +194,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -708,7 +708,7 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, foid): def delete(self, gid, sid, did, scid, foid=None):
""" """
Drops the Foreign Table. Drops the Foreign Table.
@ -719,6 +719,13 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
scid: Schema Id scid: Schema Id
foid: Foreign Table Id foid: Foreign Table Id
""" """
if foid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [foid]}
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
cascade = True cascade = True
@ -726,47 +733,41 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
cascade = False cascade = False
try: try:
# Fetch Name and Schema Name to delete the foreign table. for foid in data['ids']:
SQL = render_template("/".join([self.template_path, # Fetch Name and Schema Name to delete the foreign table.
'delete.sql']), scid=scid, SQL = render_template("/".join([self.template_path,
foid=foid) 'delete.sql']), scid=scid,
status, res = self.conn.execute_2darray(SQL) foid=foid)
if not status: status, res = self.conn.execute_2darray(SQL)
return internal_server_error(errormsg=res) if not status:
return internal_server_error(errormsg=res)
if not res['rows']: if not res['rows']:
return make_json_response( return make_json_response(
success=0, success=0,
errormsg=gettext( errormsg=gettext(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=gettext( info=gettext(
'The specified foreign table could not be found.\n' 'The specified foreign table could not be found.\n'
)
) )
)
name = res['rows'][0]['name'] name = res['rows'][0]['name']
basensp = res['rows'][0]['basensp'] basensp = res['rows'][0]['basensp']
SQL = render_template("/".join([self.template_path, SQL = render_template("/".join([self.template_path,
'delete.sql']), 'delete.sql']),
name=name, name=name,
basensp=basensp, basensp=basensp,
cascade=cascade) cascade=cascade)
status, res = self.conn.execute_scalar(SQL) status, res = self.conn.execute_scalar(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("Foreign Table dropped"), info=gettext("Foreign Table dropped")
data={
'id': foid,
'scid': scid,
'sid': sid,
'gid': gid,
'did': did
}
) )
except Exception as e: except Exception as e:

View File

@ -0,0 +1,99 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import print_function
import uuid
import json
from pgadmin.browser.server_groups.servers.databases.foreign_data_wrappers. \
foreign_servers.tests import utils as fsrv_utils
from pgadmin.browser.server_groups.servers.databases.foreign_data_wrappers. \
tests import utils as fdw_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 . import utils as ft_utils
class ForeignTableDeleteMultipleTestCase(BaseTestGenerator):
"""
This class will delete foreign table under database node.
"""
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for foreign table node.
('Check foreign table Node', dict(url='/browser/foreign_table/obj/'))
]
def setUp(self):
""" This function will create foreign data wrapper, foreign server
and foreign table. """
super(ForeignTableDeleteMultipleTestCase, self).setUp()
self.schema_data = parent_node_dict['schema'][-1]
self.server_id = self.schema_data['server_id']
self.db_id = self.schema_data['db_id']
self.db_name = parent_node_dict["database"][-1]["db_name"]
self.schema_name = self.schema_data['schema_name']
self.schema_id = self.schema_data['schema_id']
self.fdw_name = "fdw_%s" % (str(uuid.uuid4())[1:8])
self.fsrv_name = "fsrv_%s" % (str(uuid.uuid4())[1:8])
self.ft_name = "ft_%s" % (str(uuid.uuid4())[1:8])
self.fdw_id = fdw_utils.create_fdw(self.server, self.db_name,
self.fdw_name)
self.fsrv_id = fsrv_utils.create_fsrv(self.server, self.db_name,
self.fsrv_name, self.fdw_name)
self.ft_ids = [ft_utils.create_foreign_table(
self.server, self.db_name,
self.schema_name, self.fsrv_name,
"ft_%s" % (str(uuid.uuid4())[1:8])),
ft_utils.create_foreign_table(
self.server, self.db_name,
self.schema_name, self.fsrv_name,
"ft_%s" % (str(uuid.uuid4())[1:8]))
]
def runTest(self):
"""This function will delete foreign table under test database."""
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
self.server_id,
self.db_id)
if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to database.")
fsrv_response = fsrv_utils.verify_fsrv(self.server, self.db_name,
self.fsrv_name)
if not fsrv_response:
raise Exception("Could not find Foreign Server.")
data = {'ids': self.ft_ids}
delete_response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/',
content_type='html/json',
follow_redirects=True,
data=json.dumps(data))
self.assertEquals(delete_response.status_code, 200)
def tearDown(self):
""" This function disconnect the test database. """
database_utils.disconnect_database(self, self.server_id, self.db_id)

View File

@ -188,12 +188,12 @@ class FtsConfigurationView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'children': [{ 'children': [{
'get': 'children' 'get': 'children'
}], }],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
'msql': [{'get': 'msql'}, {'get': 'msql'}], 'msql': [{'get': 'msql'}, {'get': 'msql'}],
@ -531,7 +531,7 @@ class FtsConfigurationView(PGChildNodeView):
) )
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, cfgid): def delete(self, gid, sid, did, scid, cfgid=None):
""" """
This function will drop the FTS Configuration object This function will drop the FTS Configuration object
:param gid: group id :param gid: group id
@ -540,6 +540,13 @@ class FtsConfigurationView(PGChildNodeView):
:param scid: schema id :param scid: schema id
:param cfgid: FTS Configuration id :param cfgid: FTS Configuration id
""" """
if cfgid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [cfgid]}
# Below will decide if it's simple drop or drop with cascade call # Below will decide if it's simple drop or drop with cascade call
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
@ -548,49 +555,44 @@ class FtsConfigurationView(PGChildNodeView):
cascade = False cascade = False
try: try:
# Get name for FTS Configuration from cfgid for cfgid in data['ids']:
sql = render_template( # Get name for FTS Configuration from cfgid
"/".join([self.template_path, 'get_name.sql']), sql = render_template(
cfgid=cfgid "/".join([self.template_path, 'get_name.sql']),
) cfgid=cfgid
status, res = self.conn.execute_dict(sql) )
if not status: status, res = self.conn.execute_dict(sql)
return internal_server_error(errormsg=res) if not status:
return internal_server_error(errormsg=res)
if not res['rows']: if not res['rows']:
return make_json_response( return make_json_response(
success=0, success=0,
errormsg=_( errormsg=_(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=_( info=_(
'The specified FTS configuration could not be found.\n' 'The specified FTS configuration '
'could not be found.\n'
)
) )
# Drop FTS Configuration
result = res['rows'][0]
sql = render_template(
"/".join([self.template_path, 'delete.sql']),
name=result['name'],
schema=result['schema'],
cascade=cascade
) )
# Drop FTS Configuration status, res = self.conn.execute_scalar(sql)
result = res['rows'][0] if not status:
sql = render_template( return internal_server_error(errormsg=res)
"/".join([self.template_path, 'delete.sql']),
name=result['name'],
schema=result['schema'],
cascade=cascade
)
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=_("FTS Configuration dropped"), info=_("FTS Configuration dropped")
data={
'id': cfgid,
'sid': sid,
'gid': gid,
'did': did,
'scid': scid
}
) )
except Exception as e: except Exception as e:

View File

@ -452,6 +452,7 @@ define('pgadmin.node.fts_configuration', [
// Defining model for FTS Configuration node // Defining model for FTS Configuration node
model: pgAdmin.Browser.Node.Model.extend({ model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, // FTS Configuration name name: undefined, // FTS Configuration name
owner: undefined, // FTS Configuration owner owner: undefined, // FTS Configuration owner

View File

@ -0,0 +1,89 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import print_function
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 . import utils as fts_configuration_utils
class FTSConfDeleteMultipleTestCase(BaseTestGenerator):
""" This class will delete added FTS configurations under schema node. """
scenarios = [
# Fetching default URL for fts_configuration node.
('Fetch FTS configuration Node URL',
dict(url='/browser/fts_configuration/obj/'))
]
def setUp(self):
""" This function will create FTS configuration."""
schema_data = parent_node_dict['schema'][-1]
self.schema_name = schema_data['schema_name']
self.schema_id = schema_data['schema_id']
self.server_id = schema_data['server_id']
self.db_id = schema_data['db_id']
self.db_name = parent_node_dict["database"][-1]["db_name"]
self.fts_conf_ids = [fts_configuration_utils.create_fts_configuration(
self.server,
self.db_name,
self.schema_name,
"fts_conf_%s" % str(uuid.uuid4())[1:8]),
fts_configuration_utils.create_fts_configuration(
self.server,
self.db_name,
self.schema_name,
"fts_conf_%s" % str(uuid.uuid4())[1:8])
]
def runTest(self):
""" This function will delete the FTS configurations under test
schema. """
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
self.server_id,
self.db_id)
if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to database.")
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.")
data = {'ids': self.fts_conf_ids}
delete_response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/',
follow_redirects=True,
data=json.dumps(data),
content_type='html/json')
self.assertEquals(delete_response.status_code, 200)
def tearDown(self):
"""This function disconnect the test database."""
database_utils.disconnect_database(self, self.server_id,
self.db_id)

View File

@ -180,12 +180,12 @@ class FtsDictionaryView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'children': [{ 'children': [{
'get': 'children' 'get': 'children'
}], }],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
'msql': [{'get': 'msql'}, {'get': 'msql'}], 'msql': [{'get': 'msql'}, {'get': 'msql'}],
@ -526,7 +526,7 @@ class FtsDictionaryView(PGChildNodeView):
) )
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, dcid): def delete(self, gid, sid, did, scid, dcid=None):
""" """
This function will drop the FTS Dictionary object This function will drop the FTS Dictionary object
:param gid: group id :param gid: group id
@ -535,6 +535,13 @@ class FtsDictionaryView(PGChildNodeView):
:param scid: schema id :param scid: schema id
:param dcid: FTS Dictionary id :param dcid: FTS Dictionary id
""" """
if dcid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [dcid]}
# Below will decide if it's simple drop or drop with cascade call # Below will decide if it's simple drop or drop with cascade call
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
@ -543,46 +550,43 @@ class FtsDictionaryView(PGChildNodeView):
cascade = False cascade = False
try: try:
# Get name for FTS Dictionary from dcid for dcid in data['ids']:
sql = render_template("/".join([self.template_path, 'delete.sql']), # Get name for FTS Dictionary from dcid
dcid=dcid) sql = render_template("/".join([self.template_path,
status, res = self.conn.execute_dict(sql) 'delete.sql']),
if not status: dcid=dcid)
return internal_server_error(errormsg=res) status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
if not res['rows']: if not res['rows']:
return make_json_response( return make_json_response(
success=0, success=0,
errormsg=_( errormsg=_(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=_( info=_(
'The specified FTS dictionary could not be found.\n' 'The specified FTS dictionary '
'could not be found.\n'
)
) )
)
# Drop FTS Dictionary # Drop FTS Dictionary
result = res['rows'][0] result = res['rows'][0]
sql = render_template("/".join([self.template_path, 'delete.sql']), sql = render_template("/".join([self.template_path,
name=result['name'], 'delete.sql']),
schema=result['schema'], name=result['name'],
cascade=cascade schema=result['schema'],
) cascade=cascade
)
status, res = self.conn.execute_scalar(sql) status, res = self.conn.execute_scalar(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=_("FTS Dictionary dropped"), info=_("FTS Dictionary dropped")
data={
'id': dcid,
'sid': sid,
'gid': gid,
'did': did,
'scid': scid
}
) )
except Exception as e: except Exception as e:

View File

@ -97,6 +97,7 @@ define('pgadmin.node.fts_dictionary', [
// Defining backform model for FTS Dictionary node // Defining backform model for FTS Dictionary node
model: pgAdmin.Browser.Node.Model.extend({ model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, // FTS Dictionary name name: undefined, // FTS Dictionary name
owner: undefined, // FTS Dictionary owner owner: undefined, // FTS Dictionary owner

View File

@ -0,0 +1,104 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import print_function
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 . import utils as fts_dict_utils
class FtsDictionaryDeleteMultipleTestCase(BaseTestGenerator):
""" This class will delete the added FTS Dictionary under schema node. """
scenarios = [
# Fetching default URL for FTS dictionary node.
('Fetch FTS dictionary Node URL', dict(
url='/browser/fts_dictionary/obj/'))
]
def setUp(self):
self.schema_data = parent_node_dict['schema'][-1]
self.schema_name = self.schema_data['schema_name']
self.schema_id = self.schema_data['schema_id']
self.server_id = self.schema_data['server_id']
self.db_id = self.schema_data['db_id']
self.db_name = parent_node_dict["database"][-1]["db_name"]
self.fts_dict_name = "fts_dict_%s" % str(uuid.uuid4())[1:8]
self.fts_dict_name_1 = "fts_dict_%s" % str(uuid.uuid4())[1:8]
self.fts_dict_ids = [fts_dict_utils.create_fts_dictionary(
self.server,
self.db_name,
self.schema_name,
self.fts_dict_name),
fts_dict_utils.create_fts_dictionary(
self.server,
self.db_name,
self.schema_name,
self.fts_dict_name_1),
]
def runTest(self):
""" This function will update FTS dictionary present under
test schema. """
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
self.server_id,
self.db_id)
if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to database.")
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.")
dict_response = fts_dict_utils.verify_fts_dict(self.server,
self.db_name,
self.fts_dict_name)
if not dict_response:
raise Exception("Could not find the FTS dictionary.")
dict_response = fts_dict_utils.verify_fts_dict(self.server,
self.db_name,
self.fts_dict_name_1)
if not dict_response:
raise Exception("Could not find the FTS dictionary.")
data = {'ids': self.fts_dict_ids}
delete_response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/',
data=json.dumps(data),
content_type='html/json',
follow_redirects=True)
self.assertEquals(delete_response.status_code, 200)
def tearDown(self):
"""This function disconnect the test database."""
database_utils.disconnect_database(self, self.server_id,
self.db_id)

View File

@ -182,12 +182,12 @@ class FtsParserView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'children': [{ 'children': [{
'get': 'children' 'get': 'children'
}], }],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
'msql': [{'get': 'msql'}, {'get': 'msql'}], 'msql': [{'get': 'msql'}, {'get': 'msql'}],
@ -453,7 +453,7 @@ class FtsParserView(PGChildNodeView):
) )
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, pid): def delete(self, gid, sid, did, scid, pid=None):
""" """
This function will drop the fts_parser object This function will drop the fts_parser object
:param gid: group id :param gid: group id
@ -462,6 +462,13 @@ class FtsParserView(PGChildNodeView):
:param scid: schema id :param scid: schema id
:param pid: fts tempate id :param pid: fts tempate id
""" """
if pid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [pid]}
# Below will decide if it's simple drop or drop with cascade call # Below will decide if it's simple drop or drop with cascade call
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
@ -470,49 +477,43 @@ class FtsParserView(PGChildNodeView):
cascade = False cascade = False
try: try:
# Get name for Parser from pid for pid in data['ids']:
sql = render_template( # Get name for Parser from pid
"/".join([self.template_path, 'delete.sql']), sql = render_template(
pid=pid "/".join([self.template_path, 'delete.sql']),
) pid=pid
status, res = self.conn.execute_dict(sql) )
if not status: status, res = self.conn.execute_dict(sql)
return internal_server_error(errormsg=res) if not status:
return internal_server_error(errormsg=res)
if not res['rows']: if not res['rows']:
return make_json_response( return make_json_response(
success=0, success=0,
errormsg=_( errormsg=_(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=_( info=_(
'The specified FTS parser could not be found.\n' 'The specified FTS parser could not be found.\n'
)
) )
# Drop fts Parser
result = res['rows'][0]
sql = render_template(
"/".join([self.template_path, 'delete.sql']),
name=result['name'],
schema=result['schema'],
cascade=cascade
) )
# Drop fts Parser status, res = self.conn.execute_scalar(sql)
result = res['rows'][0] if not status:
sql = render_template( return internal_server_error(errormsg=res)
"/".join([self.template_path, 'delete.sql']),
name=result['name'],
schema=result['schema'],
cascade=cascade
)
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=_("FTS Parser dropped"), info=_("FTS Parser dropped")
data={
'id': pid,
'sid': sid,
'gid': gid,
'did': did,
'scid': scid
}
) )
except Exception as e: except Exception as e:

View File

@ -58,6 +58,7 @@ define('pgadmin.node.fts_parser', [
// Defining backform model for fts parser node // Defining backform model for fts parser node
model: pgAdmin.Browser.Node.Model.extend({ model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, // Fts parser name name: undefined, // Fts parser name
description: undefined, // Comment on parser description: undefined, // Comment on parser

View File

@ -0,0 +1,104 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import print_function
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 . import utils as fts_parser_utils
class FtsParserDeleteMultipleTestCase(BaseTestGenerator):
""" This class will delete added FTS Parser under schema node. """
scenarios = [
# Fetching default URL for FTS parser node.
('Fetch FTS parser Node URL', dict(url='/browser/fts_parser/obj/'))
]
def setUp(self):
self.schema_data = parent_node_dict['schema'][-1]
self.schema_name = self.schema_data['schema_name']
self.schema_id = self.schema_data['schema_id']
self.server_id = self.schema_data['server_id']
self.db_id = self.schema_data['db_id']
self.db_name = parent_node_dict["database"][-1]["db_name"]
self.fts_parser_name = "fts_parser_%s" % str(uuid.uuid4())[1:8]
self.fts_parser_name_1 = "fts_parser_%s" % str(uuid.uuid4())[1:8]
self.fts_parser_ids = [fts_parser_utils.create_fts_parser(
self.server,
self.db_name,
self.schema_name,
self.fts_parser_name),
fts_parser_utils.create_fts_parser(
self.server,
self.db_name,
self.schema_name,
self.fts_parser_name_1)
]
def runTest(self):
""" This function will delete FTS parser present under test schema. """
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
self.server_id,
self.db_id)
if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to database.")
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.")
parser_response = fts_parser_utils.verify_fts_parser(
self.server,
self.db_name,
self.fts_parser_name)
if not parser_response:
raise Exception("Could not find the FTS parser.")
parser_response = fts_parser_utils.verify_fts_parser(
self.server,
self.db_name,
self.fts_parser_name_1)
if not parser_response:
raise Exception("Could not find the FTS parser.")
data = {'ids': self.fts_parser_ids}
delete_response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/',
data=json.dumps(data),
content_type='html/json',
follow_redirects=True)
self.assertEquals(delete_response.status_code, 200)
def tearDown(self):
"""This function disconnect the test database."""
database_utils.disconnect_database(self, self.server_id,
self.db_id)

View File

@ -175,12 +175,12 @@ class FtsTemplateView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'children': [{ 'children': [{
'get': 'children' 'get': 'children'
}], }],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
'msql': [{'get': 'msql'}, {'get': 'msql'}], 'msql': [{'get': 'msql'}, {'get': 'msql'}],
@ -433,7 +433,7 @@ class FtsTemplateView(PGChildNodeView):
) )
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, tid): def delete(self, gid, sid, did, scid, tid=None):
""" """
This function will drop the fts_template object This function will drop the fts_template object
:param gid: group id :param gid: group id
@ -442,6 +442,13 @@ class FtsTemplateView(PGChildNodeView):
:param scid: schema id :param scid: schema id
:param tid: fts tempate id :param tid: fts tempate id
""" """
if tid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [tid]}
# Below will decide if it's simple drop or drop with cascade call # Below will decide if it's simple drop or drop with cascade call
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
@ -449,46 +456,40 @@ class FtsTemplateView(PGChildNodeView):
else: else:
cascade = False cascade = False
# Get name for template from tid for tid in data['ids']:
sql = render_template("/".join([self.template_path, 'delete.sql']), # Get name for template from tid
tid=tid) sql = render_template("/".join([self.template_path, 'delete.sql']),
status, res = self.conn.execute_dict(sql) tid=tid)
if not status: status, res = self.conn.execute_dict(sql)
return internal_server_error(errormsg=res) if not status:
return internal_server_error(errormsg=res)
if not res['rows']: if not res['rows']:
return make_json_response( return make_json_response(
success=0, success=0,
errormsg=gettext( errormsg=gettext(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=gettext( info=gettext(
'The specified FTS template could not be found.\n' 'The specified FTS template could not be found.\n'
)
) )
)
# Drop fts template # Drop fts template
result = res['rows'][0] result = res['rows'][0]
sql = render_template("/".join([self.template_path, 'delete.sql']), sql = render_template("/".join([self.template_path, 'delete.sql']),
name=result['name'], name=result['name'],
schema=result['schema'], schema=result['schema'],
cascade=cascade cascade=cascade
) )
status, res = self.conn.execute_scalar(sql) status, res = self.conn.execute_scalar(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("FTS Template dropped"), info=gettext("FTS Template dropped")
data={
'id': tid,
'sid': sid,
'gid': gid,
'did': did,
'scid': scid
}
) )
@check_precondition @check_precondition

View File

@ -58,6 +58,7 @@ define('pgadmin.node.fts_template', [
// Defining backform model for fts template node // Defining backform model for fts template node
model: pgAdmin.Browser.Node.Model.extend({ model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, // Fts template name name: undefined, // Fts template name
description: undefined, // Comment on template description: undefined, // Comment on template

View File

@ -0,0 +1,102 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import print_function
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 . import utils as fts_temp_utils
class FtsTemplateDeleteMultipleTestCase(BaseTestGenerator):
""" This class will delete new FTS template under schema node. """
scenarios = [
# Fetching default URL for FTS template node.
('Fetch FTS template Node URL', dict(url='/browser/fts_template/obj/'))
]
def setUp(self):
self.schema_data = parent_node_dict['schema'][-1]
self.schema_name = self.schema_data['schema_name']
self.schema_id = self.schema_data['schema_id']
self.server_id = self.schema_data['server_id']
self.db_id = self.schema_data['db_id']
self.db_name = parent_node_dict["database"][-1]["db_name"]
self.fts_temp_name = "fts_temp_%s" % str(uuid.uuid4())[1:8]
self.fts_temp_name_1 = "fts_temp_%s" % str(uuid.uuid4())[1:8]
self.fts_temp_ids = [fts_temp_utils.create_fts_template(
self.server,
self.db_name,
self.schema_name,
self.fts_temp_name),
fts_temp_utils.create_fts_template(
self.server,
self.db_name,
self.schema_name,
self.fts_temp_name_1)
]
def runTest(self):
""" This function will delete FTS template present under
test schema. """
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
self.server_id,
self.db_id)
if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to database.")
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.")
fts_response = fts_temp_utils.verify_fts_template(self.server,
self.db_name,
self.fts_temp_name)
if not fts_response:
raise Exception("Could not find the FTS template.")
fts_response = fts_temp_utils.verify_fts_template(self.server,
self.db_name,
self.fts_temp_name_1)
if not fts_response:
raise Exception("Could not find the FTS template.")
data = {'ids': self.fts_temp_ids}
delete_response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/',
data=json.dumps(data),
content_type='html/json',
follow_redirects=True)
self.assertEquals(delete_response.status_code, 200)
def tearDown(self):
"""This function disconnect the test database."""
database_utils.disconnect_database(self, self.server_id,
self.db_id)

View File

@ -199,9 +199,9 @@ class FunctionView(PGChildNodeView, DataTypeReader):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'nodes'}, {'get': 'nodes'}], 'nodes': [{'get': 'nodes'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -801,7 +801,7 @@ class FunctionView(PGChildNodeView, DataTypeReader):
) )
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, fnid): def delete(self, gid, sid, did, scid, fnid=None):
""" """
Drop the Function. Drop the Function.
@ -812,6 +812,12 @@ class FunctionView(PGChildNodeView, DataTypeReader):
scid: Schema Id scid: Schema Id
fnid: Function Id fnid: Function Id
""" """
if fnid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [fnid]}
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
@ -820,45 +826,39 @@ class FunctionView(PGChildNodeView, DataTypeReader):
cascade = False cascade = False
try: try:
# Fetch Name and Schema Name to delete the Function. for fnid in data['ids']:
SQL = render_template("/".join([self.sql_template_path, # Fetch Name and Schema Name to delete the Function.
'delete.sql']), scid=scid, SQL = render_template("/".join([self.sql_template_path,
fnid=fnid) 'delete.sql']), scid=scid,
status, res = self.conn.execute_2darray(SQL) fnid=fnid)
if not status: status, res = self.conn.execute_2darray(SQL)
return internal_server_error(errormsg=res) if not status:
return internal_server_error(errormsg=res)
if not res['rows']: if not res['rows']:
return make_json_response( return make_json_response(
success=0, success=0,
errormsg=gettext( errormsg=gettext(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=gettext( info=gettext(
'The specified function could not be found.\n' 'The specified function could not be found.\n'
)
) )
)
SQL = render_template("/".join([self.sql_template_path, SQL = render_template("/".join([self.sql_template_path,
'delete.sql']), 'delete.sql']),
name=res['rows'][0]['name'], name=res['rows'][0]['name'],
func_args=res['rows'][0]['func_args'], func_args=res['rows'][0]['func_args'],
nspname=res['rows'][0]['nspname'], nspname=res['rows'][0]['nspname'],
cascade=cascade) cascade=cascade)
status, res = self.conn.execute_scalar(SQL) status, res = self.conn.execute_scalar(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("Function dropped."), info=gettext("Function dropped.")
data={
'id': fnid,
'scid': scid,
'sid': sid,
'gid': gid,
'did': did
}
) )
except Exception as e: except Exception as e:

View File

@ -60,6 +60,7 @@ define('pgadmin.node.trigger_function', [
}, },
model: pgBrowser.Node.Model.extend({ model: pgBrowser.Node.Model.extend({
idAttribute: 'oid',
initialize: function(attrs, args) { initialize: function(attrs, args) {
var isNew = (_.size(attrs) === 0); var isNew = (_.size(attrs) === 0);
if (isNew) { if (isNew) {

View File

@ -0,0 +1,56 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import uuid
import json
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils
from . import utils as funcs_utils
class FunctionDeleteTestCase(BaseTestGenerator):
""" This class will delete the function under schema node. """
scenarios = [
# Fetching default URL for function node.
('Fetch Function Node URL',
dict(url='/browser/function/obj/'))
]
def runTest(self):
""" This function will delete function under database node. """
super(FunctionDeleteTestCase, self).setUp()
self = funcs_utils.set_up(self)
func_name = "test_function_delete_%s" % str(uuid.uuid4())[1:8]
function_info = funcs_utils.create_function(
self.server, self.db_name, self.schema_name, func_name)
func_name_1 = "test_function_delete_%s" % str(uuid.uuid4())[1:8]
function_info_1 = funcs_utils.create_function(
self.server, self.db_name, self.schema_name, func_name_1)
data = {'ids': [function_info[0], function_info_1[0]]}
response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/',
data=json.dumps(data),
follow_redirects=True,
content_type='html/json'
)
self.assertEquals(response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)
def tearDown(self):
pass

View File

@ -0,0 +1,64 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import uuid
import json
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils
from . import utils as funcs_utils
class procedureDeleteMultipleTestCase(BaseTestGenerator):
""" This class will delete the procedure under schema node. """
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for procedure node.
('Fetch Procedure Node URL',
dict(url='/browser/procedure/obj/'))
]
def runTest(self):
""" This function will delete procedure under database node. """
super(procedureDeleteMultipleTestCase, self).setUp()
self = funcs_utils.set_up(self)
if self.server_type == "pg" and\
self.server_version < 110000:
message = "Procedures are not supported by PG < 110000."
self.skipTest(message)
func_name = "test_procedure_delete_%s" % str(uuid.uuid4())[1:8]
proc_info = funcs_utils.create_procedure(
self.server, self.db_name, self.schema_name, func_name,
self.server_type, self.server_version)
func_name_1 = "test_procedure_delete_%s" % str(uuid.uuid4())[1:8]
proc_info_1 = funcs_utils.create_procedure(
self.server, self.db_name, self.schema_name, func_name_1,
self.server_type, self.server_version)
data = {'ids': [proc_info[0], proc_info_1[0]]}
response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/',
data=json.dumps(data),
content_type='html/json',
follow_redirects=True
)
self.assertEquals(response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)
def tearDown(self):
pass

View File

@ -0,0 +1,59 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import uuid
import json
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from pgadmin.utils.route import BaseTestGenerator
from regression.python_test_utils import test_utils as utils
from . import utils as funcs_utils
class TriggerFuncDeleteMultipleTestCase(BaseTestGenerator):
""" This class will delete the trigger function under schema node. """
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for trigger function node.
('Fetch Trigger Function Node URL',
dict(url='/browser/trigger_function/obj/'))
]
def runTest(self):
""" This function will delete trigger function under database node. """
super(TriggerFuncDeleteMultipleTestCase, self).setUp()
self = funcs_utils.set_up(self)
func_name = "test_event_delete_%s" % str(uuid.uuid4())[1:8]
function_info = funcs_utils.create_trigger_function(
self.server, self.db_name, self.schema_name, func_name,
self.server_version)
func_name_1 = "test_event_delete_%s" % str(uuid.uuid4())[1:8]
function_info_1 = funcs_utils.create_trigger_function(
self.server, self.db_name, self.schema_name, func_name_1,
self.server_version)
data = {'ids': [function_info[0], function_info_1[0]]}
response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/',
data=json.dumps(data),
follow_redirects=True,
content_type='html/json'
)
self.assertEquals(response.status_code, 200)
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)
def tearDown(self):
pass

View File

@ -99,9 +99,9 @@ class PackageView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'nodes'}, {'get': 'nodes'}], 'nodes': [{'get': 'nodes'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -412,7 +412,7 @@ class PackageView(PGChildNodeView):
) )
@check_precondition(action='delete') @check_precondition(action='delete')
def delete(self, gid, sid, did, scid, pkgid): def delete(self, gid, sid, did, scid, pkgid=None):
""" """
This function will drop the object This function will drop the object
@ -426,6 +426,14 @@ class PackageView(PGChildNodeView):
Returns: Returns:
""" """
if pkgid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [pkgid]}
# Below will decide if it's simple drop or drop with cascade call # Below will decide if it's simple drop or drop with cascade call
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
@ -434,44 +442,40 @@ class PackageView(PGChildNodeView):
cascade = False cascade = False
try: try:
SQL = render_template( for pkgid in data['ids']:
"/".join([self.template_path, 'properties.sql']), scid=scid, SQL = render_template(
pkgid=pkgid) "/".join([self.template_path, 'properties.sql']),
status, res = self.conn.execute_dict(SQL) scid=scid,
if not status: pkgid=pkgid)
return internal_server_error(errormsg=res) status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if not res['rows']: if not res['rows']:
return make_json_response( return make_json_response(
success=0, success=0,
errormsg=_( errormsg=_(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=_( info=_(
'The specified package could not be found.\n' 'The specified package could not be found.\n'
)
) )
)
res['rows'][0]['schema'] = self.schema res['rows'][0]['schema'] = self.schema
SQL = render_template("/".join([self.template_path, 'delete.sql']), SQL = render_template("/".join([self.template_path,
data=res['rows'][0], 'delete.sql']),
cascade=cascade) data=res['rows'][0],
cascade=cascade)
status, res = self.conn.execute_scalar(SQL) status, res = self.conn.execute_scalar(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=_("Package dropped"), info=_("Package dropped")
data={
'id': pkgid,
'scid': scid,
'sid': sid,
'gid': gid,
'did': did
}
) )
except Exception as e: except Exception as e:

View File

@ -12,6 +12,8 @@ define('pgadmin.node.edbfunc', [
label: gettext('Functions'), label: gettext('Functions'),
type: 'coll-edbfunc', type: 'coll-edbfunc',
columns: ['name', 'funcowner', 'description'], columns: ['name', 'funcowner', 'description'],
canDrop: false,
canDropCascade: false,
}); });
} }
@ -37,6 +39,7 @@ define('pgadmin.node.edbfunc', [
canDrop: false, canDrop: false,
canDropCascade: false, canDropCascade: false,
model: pgBrowser.Node.Model.extend({ model: pgBrowser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, name: undefined,
oid: undefined, oid: undefined,

View File

@ -16,6 +16,8 @@ define('pgadmin.node.edbproc', [
type: 'coll-edbproc', type: 'coll-edbproc',
columns: ['name', 'funcowner', 'description'], columns: ['name', 'funcowner', 'description'],
hasStatistics: true, hasStatistics: true,
canDrop: false,
canDropCascade: false,
}); });
} }

View File

@ -12,6 +12,8 @@ define('pgadmin.node.edbvar', [
label: gettext('Variables'), label: gettext('Variables'),
type: 'coll-edbvar', type: 'coll-edbvar',
columns: ['name', 'funcowner', 'description'], columns: ['name', 'funcowner', 'description'],
canDrop: false,
canDropCascade: false,
}); });
} }
@ -36,6 +38,7 @@ define('pgadmin.node.edbvar', [
canDrop: false, canDrop: false,
canDropCascade: false, canDropCascade: false,
model: pgBrowser.Node.Model.extend({ model: pgBrowser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, name: undefined,
oid: undefined, oid: undefined,

View File

@ -73,6 +73,7 @@ define('pgadmin.node.package', [
}, },
// Define the model for package node. // Define the model for package node.
model: pgBrowser.Node.Model.extend({ model: pgBrowser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, name: undefined,
oid: undefined, oid: undefined,

View File

@ -0,0 +1,101 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, 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 import server_utils as server_utils
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as package_utils
class PackageDeleteMultipleTestCase(BaseTestGenerator):
""" This class will delete new package under test schema. """
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for package node.
('Fetch Package Node URL', dict(
url='/browser/package/obj/'))
]
def setUp(self):
super(PackageDeleteMultipleTestCase, self).setUp()
schema_info = parent_node_dict["schema"][-1]
self.schema_id = schema_info["schema_id"]
self.schema_name = schema_info["schema_name"]
self.db_name = parent_node_dict["database"][-1]["db_name"]
self.server_id = schema_info["server_id"]
self.db_id = schema_info["db_id"]
server_con = server_utils.connect_server(self, self.server_id)
if server_con:
if "type" in server_con["data"]:
if server_con["data"]["type"] == "pg":
message = "Packages are not supported by PG."
self.skipTest(message)
self.pkg_name = "pkg_%s" % str(uuid.uuid4())[1:8]
self.proc_name = "proc_%s" % str(uuid.uuid4())[1:8]
self.pkg_name_1 = "pkg_%s" % str(uuid.uuid4())[1:8]
self.proc_name_1 = "proc_%s" % str(uuid.uuid4())[1:8]
self.package_ids = [package_utils.create_package(self.server,
self.db_name,
self.schema_name,
self.pkg_name,
self.proc_name),
package_utils.create_package(self.server,
self.db_name,
self.schema_name,
self.pkg_name_1,
self.proc_name_1)
]
def runTest(self):
""" This function will delete package under test schema. """
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
self.server_id,
self.db_id)
if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to database.")
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.")
data = {'ids': self.package_ids}
delete_response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/',
data=json.dumps(data),
content_type='html/json',
follow_redirects=True)
self.assertEquals(delete_response.status_code, 200)
def tearDown(self):
"""This function disconnect the test database."""
database_utils.disconnect_database(self, self.server_id,
self.db_id)

View File

@ -104,9 +104,9 @@ class SequenceView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'nodes'}, {'get': 'nodes'}], 'nodes': [{'get': 'nodes'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -396,7 +396,7 @@ class SequenceView(PGChildNodeView):
) )
@check_precondition(action='delete') @check_precondition(action='delete')
def delete(self, gid, sid, did, scid, seid): def delete(self, gid, sid, did, scid, seid=None):
""" """
This function will drop the object This function will drop the object
@ -410,6 +410,13 @@ class SequenceView(PGChildNodeView):
Returns: Returns:
""" """
if seid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [seid]}
# Below will decide if it's simple drop or drop with cascade call # Below will decide if it's simple drop or drop with cascade call
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
@ -418,43 +425,37 @@ class SequenceView(PGChildNodeView):
cascade = False cascade = False
try: try:
SQL = render_template( for seid in data['ids']:
"/".join([self.template_path, 'properties.sql']), SQL = render_template(
scid=scid, seid=seid "/".join([self.template_path, 'properties.sql']),
) scid=scid, seid=seid
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if not res['rows']:
return make_json_response(
success=0,
errormsg=_(
'Error: Object not found.'
),
info=_(
'The specified sequence could not be found.\n'
)
) )
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
SQL = render_template( if not res['rows']:
"/".join([self.template_path, 'delete.sql']), return make_json_response(
data=res['rows'][0], cascade=cascade success=0,
) errormsg=_(
status, res = self.conn.execute_scalar(SQL) 'Error: Object not found.'
if not status: ),
return internal_server_error(errormsg=res) info=_(
'The specified sequence could not be found.\n'
)
)
SQL = render_template(
"/".join([self.template_path, 'delete.sql']),
data=res['rows'][0], cascade=cascade
)
status, res = self.conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=_("Sequence dropped"), info=_("Sequence dropped")
data={
'id': seid,
'scid': scid,
'sid': sid,
'gid': gid,
'did': did
}
) )
except Exception as e: except Exception as e:

View File

@ -61,6 +61,7 @@ define('pgadmin.node.sequence', [
}, },
// Define the model for sequence node. // Define the model for sequence node.
model: pgBrowser.Node.Model.extend({ model: pgBrowser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, name: undefined,
oid: undefined, oid: undefined,

View File

@ -0,0 +1,93 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, 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 . import utils as sequence_utils
class SequenceDeleteMultipleTestCase(BaseTestGenerator):
"""This class will delete added sequence under schema node."""
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for sequence node.
('Fetch sequence Node URL', dict(url='/browser/sequence/obj/'))
]
def setUp(self):
super(SequenceDeleteMultipleTestCase, self).setUp()
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 sequence.")
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 sequence.")
self.sequence_name = "test_sequence_delete_%s" % str(uuid.uuid4())[1:8]
self.sequence_name_1 = "test_sequence_delete_%s" %\
str(uuid.uuid4())[1:8]
self.sequence_ids = [sequence_utils.create_sequences(
self.server,
self.db_name,
self.schema_name,
self.sequence_name),
sequence_utils.create_sequences(
self.server,
self.db_name,
self.schema_name,
self.sequence_name_1)
]
def runTest(self):
""" This function will delete added sequence under schema node. """
sequence_response = sequence_utils.verify_sequence(self.server,
self.db_name,
self.sequence_name)
if not sequence_response:
raise Exception("Could not find the sequence to delete.")
sequence_response = sequence_utils.verify_sequence(self.server,
self.db_name,
self.sequence_name_1
)
if not sequence_response:
raise Exception("Could not find the sequence to delete.")
data = json.dumps({'ids': self.sequence_ids})
response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_id) + '/',
follow_redirects=True,
data=data,
content_type='html/json'
)
self.assertEquals(response.status_code, 200)
def tearDown(self):
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)

View File

@ -11,6 +11,8 @@ define('pgadmin.node.catalog', [
label: gettext('Catalogs'), label: gettext('Catalogs'),
type: 'coll-catalog', type: 'coll-catalog',
columns: ['name', 'namespaceowner', 'description'], columns: ['name', 'namespaceowner', 'description'],
canDrop: false,
canDropCascade: false,
}); });
} }
// Extend the browser's node class for catalog node // Extend the browser's node class for catalog node

View File

@ -306,6 +306,7 @@ define('pgadmin.node.schema', [
return pgBrowser.Nodes['database'].is_conn_allow.call(this, node); return pgBrowser.Nodes['database'].is_conn_allow.call(this, node);
}, },
model: pgBrowser.Node.Model.extend({ model: pgBrowser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, name: undefined,
namespaceowner: undefined, namespaceowner: undefined,

View File

@ -165,9 +165,9 @@ class SynonymView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -468,7 +468,7 @@ class SynonymView(PGChildNodeView):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, syid): def delete(self, gid, sid, did, scid, syid=None):
""" """
This function will delete existing the synonym object This function will delete existing the synonym object
@ -479,42 +479,44 @@ class SynonymView(PGChildNodeView):
scid: Schema ID scid: Schema ID
syid: Synonym ID syid: Synonym ID
""" """
if syid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [syid]}
# Below will decide if it's simple drop or drop with cascade call # Below will decide if it's simple drop or drop with cascade call
try: try:
SQL = render_template("/".join([self.template_path, for syid in data['ids']:
'properties.sql']), SQL = render_template("/".join([self.template_path,
scid=scid, syid=syid) 'properties.sql']),
scid=scid, syid=syid)
status, res = self.conn.execute_dict(SQL) status, res = self.conn.execute_dict(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
if len(res['rows']) > 0: if len(res['rows']) > 0:
data = res['rows'][0] data = res['rows'][0]
else: else:
return gone( return gone(
gettext('The specified synonym could not be found.') gettext('The specified synonym could not be found.')
) )
SQL = render_template("/".join([self.template_path, SQL = render_template("/".join([self.template_path,
'delete.sql']), 'delete.sql']),
data=data, data=data,
conn=self.conn) conn=self.conn)
status, res = self.conn.execute_scalar(SQL) status, res = self.conn.execute_scalar(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("Synonym dropped"), info=gettext("Synonym dropped")
data={
'id': syid,
'scid': scid,
'did': did
}
) )
except Exception as e: except Exception as e:

View File

@ -0,0 +1,103 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import uuid
import json
from pgadmin.browser.server_groups.servers.databases.schemas.sequences.tests \
import utils as sequence_utils
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 import server_utils as server_utils
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as synonym_utils
class SynonymDeleteMultipleTestCase(BaseTestGenerator):
"""This class will delete added synonym under schema node."""
skip_on_database = ['gpdb']
scenarios = [
# Fetching default URL for synonym node.
('Fetch synonym Node URL', dict(url='/browser/synonym/obj/'))
]
def setUp(self):
super(SynonymDeleteMultipleTestCase, self).setUp()
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"]
server_con = server_utils.connect_server(self, self.server_id)
if server_con:
if "type" in server_con["data"]:
if server_con["data"]["type"] == "pg":
message = "Synonyms are not supported by PG."
self.skipTest(message)
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 synonym.")
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 the synonym.")
self.sequence_name = "test_sequence_synonym_%s" % \
str(uuid.uuid4())[1:8]
self.sequence_id = sequence_utils.create_sequences(
self.server, self.db_name, self.schema_name, self.sequence_name)
self.synonym_name = "test_synonym_delete_%s" % str(uuid.uuid4())[1:8]
synonym_utils.create_synonym(self.server,
self.db_name,
self.schema_name,
self.synonym_name,
self.sequence_name)
self.synonym_name_1 = "test_synonym_delete_%s" % str(uuid.uuid4())[1:8]
synonym_utils.create_synonym(self.server,
self.db_name,
self.schema_name,
self.synonym_name_1,
self.sequence_name)
def runTest(self):
"""This function will delete synonym under schema node."""
synonym_response = synonym_utils.verify_synonym(self.server,
self.db_name,
self.synonym_name)
if not synonym_response:
raise Exception("No synonym node to delete.")
synonym_response = synonym_utils.verify_synonym(self.server,
self.db_name,
self.synonym_name_1)
if not synonym_response:
raise Exception("No synonym node to delete.")
data = {'ids': [self.synonym_name, self.synonym_name_1]}
response = self.tester.delete(
self.url + str(utils.SERVER_GROUP) + '/' +
str(self.server_id) + '/' + str(self.db_id) + '/' +
str(self.schema_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)

View File

@ -212,9 +212,9 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -1056,7 +1056,7 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@BaseTableView.check_precondition @BaseTableView.check_precondition
def delete(self, gid, sid, did, scid, tid): def delete(self, gid, sid, did, scid, tid=None):
""" """
This function will deletes the table object This function will deletes the table object
@ -1067,29 +1067,45 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
scid: Schema ID scid: Schema ID
tid: Table ID tid: Table ID
""" """
if tid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [tid]}
try: try:
SQL = render_template( for tid in data['ids']:
"/".join([self.table_template_path, 'properties.sql']), SQL = render_template(
did=did, scid=scid, tid=tid, "/".join([self.table_template_path, 'properties.sql']),
datlastsysoid=self.datlastsysoid did=did, scid=scid, tid=tid,
) datlastsysoid=self.datlastsysoid
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if not res['rows']:
return make_json_response(
success=0,
errormsg=gettext(
'Error: Object not found.'
),
info=gettext(
'The specified table could not be found.\n'
)
) )
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
return super(TableView, self).delete(gid, sid, did, scid, tid, res) if not res['rows']:
return make_json_response(
success=0,
errormsg=gettext(
'Error: Object not found.'
),
info=gettext(
'The specified table could not be found.\n'
)
)
status, res = super(TableView, self).delete(gid, sid, did,
scid, tid, res)
if not status:
return internal_server_error(errormsg=res)
return make_json_response(
success=1,
info=gettext("Table dropped")
)
except Exception as e: except Exception as e:
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))

View File

@ -181,7 +181,7 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'nodes'}, {'get': 'nodes'}], 'nodes': [{'get': 'nodes'}, {'get': 'nodes'}],
@ -609,7 +609,7 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
) )
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, tid, clid): def delete(self, gid, sid, did, scid, tid, clid=None):
""" """
This function will updates existing the schema object This function will updates existing the schema object
@ -621,42 +621,49 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
tid: Table ID tid: Table ID
clid: Column ID clid: Column ID
""" """
if clid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [clid]}
# We will first fetch the column name for current request # We will first fetch the column name for current request
# so that we create template for dropping column # so that we create template for dropping column
try: try:
for clid in data['ids']:
SQL = render_template( SQL = render_template(
"/".join([self.template_path, 'properties.sql']), "/".join([self.template_path, 'properties.sql']),
tid=tid, clid=clid, tid=tid, clid=clid,
show_sys_objects=self.blueprint.show_system_objects show_sys_objects=self.blueprint.show_system_objects
)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if not res['rows']:
return make_json_response(
success=0,
errormsg=gettext(
'Error: Object not found.'
),
info=gettext(
'The specified column could not be found.\n'
)
) )
data = dict(res['rows'][0]) status, res = self.conn.execute_dict(SQL)
# We will add table & schema as well if not status:
data['schema'] = self.schema return internal_server_error(errormsg=res)
data['table'] = self.table
SQL = render_template("/".join([self.template_path, if not res['rows']:
'delete.sql']), return make_json_response(
data=data, conn=self.conn) success=0,
status, res = self.conn.execute_scalar(SQL) errormsg=gettext(
if not status: 'Error: Object not found.'
return internal_server_error(errormsg=res) ),
info=gettext(
'The specified column could not be found.\n'
)
)
data = dict(res['rows'][0])
# We will add table & schema as well
data['schema'] = self.schema
data['table'] = self.table
SQL = render_template("/".join([self.template_path,
'delete.sql']),
data=data, conn=self.conn)
status, res = self.conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,

View File

@ -0,0 +1,91 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import uuid
import json
from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
import utils as tables_utils
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 . import utils as columns_utils
class ColumnDeleteMultipleTestCase(BaseTestGenerator):
"""This class will delete column under table node."""
scenarios = [
('Delete column Node URL', dict(url='/browser/column/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_column_%s" % (str(uuid.uuid4())[1:8])
self.table_id = tables_utils.create_table(self.server, self.db_name,
self.schema_name,
self.table_name)
self.column_name = "test_column_delete_%s" % (str(uuid.uuid4())[1:8])
self.column_name_1 = "test_column_delete_%s" % (str(uuid.uuid4())[1:8])
self.column_ids = [columns_utils.create_column(self.server,
self.db_name,
self.schema_name,
self.table_name,
self.column_name),
columns_utils.create_column(self.server,
self.db_name,
self.schema_name,
self.table_name,
self.column_name_1)
]
def runTest(self):
"""This function will drop column under table node."""
col_response = columns_utils.verify_column(self.server, self.db_name,
self.column_name)
if not col_response:
raise Exception("Could not find the column to drop.")
col_response = columns_utils.verify_column(self.server, self.db_name,
self.column_name_1)
if not col_response:
raise Exception("Could not find the column to drop.")
data = {'ids': self.column_ids}
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) + '/',
follow_redirects=True,
data=json.dumps(data),
content_type='html/json'
)
self.assertEquals(response.status_code, 200)
def tearDown(self):
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)

View File

@ -173,9 +173,9 @@ class CheckConstraintView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -585,7 +585,7 @@ class CheckConstraintView(PGChildNodeView):
) )
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, tid, cid): def delete(self, gid, sid, did, scid, tid, cid=None):
""" """
Drops the Check Constraint object. Drops the Check Constraint object.
@ -597,45 +597,47 @@ class CheckConstraintView(PGChildNodeView):
tid: Check Id tid: Check Id
cid: Check Constraint Id cid: Check Constraint Id
""" """
if cid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [cid]}
try: try:
SQL = render_template("/".join([self.template_path, for cid in data['ids']:
'properties.sql']), SQL = render_template("/".join([self.template_path,
tid=tid, cid=cid) 'properties.sql']),
status, res = self.conn.execute_dict(SQL) tid=tid, cid=cid)
status, res = self.conn.execute_dict(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
if not res['rows']: if not res['rows']:
return make_json_response( return make_json_response(
success=0, success=0,
errormsg=_( errormsg=_(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=_( info=_(
'The specified check constraint could not be found.\n' 'The specified check constraint '
'could not be found.\n'
)
) )
)
data = res['rows'][0] data = res['rows'][0]
SQL = render_template("/".join([self.template_path, SQL = render_template("/".join([self.template_path,
'delete.sql']), 'delete.sql']),
data=data) data=data)
status, res = self.conn.execute_scalar(SQL) status, res = self.conn.execute_scalar(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=_("Check constraint dropped."), info=_("Check constraint dropped.")
data={
'id': tid,
'scid': scid,
'sid': sid,
'gid': gid,
'did': did
}
) )
except Exception as e: except Exception as e:

View File

@ -84,7 +84,6 @@ define('pgadmin.node.check_constraint', [
canDrop: schemaChildTreeNode.isTreeItemOfChildOfSchema, canDrop: schemaChildTreeNode.isTreeItemOfChildOfSchema,
model: pgAdmin.Browser.Node.Model.extend({ model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid', idAttribute: 'oid',
defaults: { defaults: {
name: undefined, name: undefined,
oid: undefined, oid: undefined,

View File

@ -200,9 +200,9 @@ class ExclusionConstraintView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -713,6 +713,13 @@ class ExclusionConstraintView(PGChildNodeView):
Returns: Returns:
""" """
if exid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [exid]}
# Below code will decide if it's simple drop or drop with cascade call # Below code will decide if it's simple drop or drop with cascade call
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
@ -720,46 +727,42 @@ class ExclusionConstraintView(PGChildNodeView):
else: else:
cascade = False cascade = False
try: try:
sql = render_template( for exid in data['ids']:
"/".join([self.template_path, 'get_name.sql']), sql = render_template(
cid=exid "/".join([self.template_path, 'get_name.sql']),
) cid=exid
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
if not res['rows']:
return make_json_response(
success=0,
errormsg=_(
'Error: Object not found.'
),
info=_(
'The specified exclusion constraint could not '
'be found.\n'
)
) )
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
data = res['rows'][0] if not res['rows']:
data['schema'] = self.schema return make_json_response(
data['table'] = self.table success=0,
errormsg=_(
'Error: Object not found.'
),
info=_(
'The specified exclusion constraint could not '
'be found.\n'
)
)
sql = render_template("/".join([self.template_path, 'delete.sql']), data = res['rows'][0]
data=data, data['schema'] = self.schema
cascade=cascade) data['table'] = self.table
status, res = self.conn.execute_scalar(sql)
if not status: sql = render_template("/".join([self.template_path,
return internal_server_error(errormsg=res) 'delete.sql']),
data=data,
cascade=cascade)
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=_("Exclusion constraint dropped."), info=_("Exclusion constraint dropped.")
data={
'id': exid,
'sid': sid,
'gid': gid,
'did': did
}
) )
except Exception as e: except Exception as e:

View File

@ -207,9 +207,9 @@ class ForeignKeyConstraintView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -756,6 +756,13 @@ class ForeignKeyConstraintView(PGChildNodeView):
Returns: Returns:
""" """
if fkid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [fkid]}
# Below code will decide if it's simple drop or drop with cascade call # Below code will decide if it's simple drop or drop with cascade call
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
@ -763,43 +770,38 @@ class ForeignKeyConstraintView(PGChildNodeView):
else: else:
cascade = False cascade = False
try: try:
sql = render_template( for fkid in data['ids']:
"/".join([self.template_path, 'get_name.sql']), fkid=fkid) sql = render_template(
status, res = self.conn.execute_dict(sql) "/".join([self.template_path, 'get_name.sql']), fkid=fkid)
if not status: status, res = self.conn.execute_dict(sql)
return internal_server_error(errormsg=res) if not status:
return internal_server_error(errormsg=res)
if not res['rows']: if not res['rows']:
return make_json_response( return make_json_response(
success=0, success=0,
errormsg=_( errormsg=_(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=_( info=_(
'The specified foreign key could not be found.\n' 'The specified foreign key could not be found.\n'
)
) )
)
data = res['rows'][0] data = res['rows'][0]
data['schema'] = self.schema data['schema'] = self.schema
data['table'] = self.table data['table'] = self.table
sql = render_template( sql = render_template(
"/".join([self.template_path, 'delete.sql']), "/".join([self.template_path, 'delete.sql']),
data=data, cascade=cascade) data=data, cascade=cascade)
status, res = self.conn.execute_scalar(sql) status, res = self.conn.execute_scalar(sql)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=_("Foreign key dropped."), info=_("Foreign key dropped.")
data={
'id': fkid,
'sid': sid,
'gid': gid,
'did': did
}
) )
except Exception as e: except Exception as e:

View File

@ -220,9 +220,9 @@ class IndexConstraintView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -746,6 +746,13 @@ class IndexConstraintView(PGChildNodeView):
Returns: Returns:
""" """
if cid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [cid]}
# Below code will decide if it's simple drop or drop with cascade call # Below code will decide if it's simple drop or drop with cascade call
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
@ -753,37 +760,39 @@ class IndexConstraintView(PGChildNodeView):
else: else:
cascade = False cascade = False
try: try:
sql = render_template( for cid in data['ids']:
"/".join([self.template_path, 'get_name.sql']), sql = render_template(
tid=tid, "/".join([self.template_path, 'get_name.sql']),
constraint_type=self.constraint_type, tid=tid,
cid=cid constraint_type=self.constraint_type,
) cid=cid
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
if not res['rows']:
return make_json_response(
success=0,
errormsg=_(
'Error: Object not found.'
),
info=_(
'The specified constraint could not be found.\n'
)
) )
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
data = res['rows'][0] if not res['rows']:
data['schema'] = self.schema return make_json_response(
data['table'] = self.table success=0,
errormsg=_(
'Error: Object not found.'
),
info=_(
'The specified constraint could not be found.\n'
)
)
sql = render_template("/".join([self.template_path, 'delete.sql']), data = res['rows'][0]
data=data, data['schema'] = self.schema
cascade=cascade) data['table'] = self.table
status, res = self.conn.execute_scalar(sql)
if not status: sql = render_template("/".join([self.template_path,
return internal_server_error(errormsg=res) 'delete.sql']),
data=data,
cascade=cascade)
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,

View File

@ -13,6 +13,8 @@ define('pgadmin.node.constraints', [
label: gettext('Constraints'), label: gettext('Constraints'),
type: 'coll-constraints', type: 'coll-constraints',
columns: ['name', 'comment'], columns: ['name', 'comment'],
canDrop: false,
canDropCascade: false,
}); });
} }

View File

@ -211,9 +211,9 @@ class IndexesView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -704,7 +704,7 @@ class IndexesView(PGChildNodeView):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, tid, idx): def delete(self, gid, sid, did, scid, tid, idx=None):
""" """
This function will updates existing the schema object This function will updates existing the schema object
@ -716,6 +716,13 @@ class IndexesView(PGChildNodeView):
tid: Table ID tid: Table ID
idx: Index ID idx: Index ID
""" """
if idx is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [idx]}
# Below will decide if it's simple drop or drop with cascade call # Below will decide if it's simple drop or drop with cascade call
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
@ -724,45 +731,42 @@ class IndexesView(PGChildNodeView):
cascade = False cascade = False
try: try:
# We will first fetch the index name for current request for idx in data['ids']:
# so that we create template for dropping index # We will first fetch the index name for current request
SQL = render_template( # so that we create template for dropping index
"/".join([self.template_path, 'properties.sql']), SQL = render_template(
did=did, tid=tid, idx=idx, datlastsysoid=self.datlastsysoid "/".join([self.template_path, 'properties.sql']),
) did=did, tid=tid, idx=idx, datlastsysoid=self.datlastsysoid
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if not res['rows']:
return make_json_response(
success=0,
errormsg=gettext(
'Error: Object not found.'
),
info=gettext(
'The specified index could not be found.\n'
)
) )
data = dict(res['rows'][0]) status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
SQL = render_template( if not res['rows']:
"/".join([self.template_path, 'delete.sql']), return make_json_response(
data=data, conn=self.conn, cascade=cascade success=0,
) errormsg=gettext(
status, res = self.conn.execute_scalar(SQL) 'Error: Object not found.'
if not status: ),
return internal_server_error(errormsg=res) info=gettext(
'The specified index could not be found.\n'
)
)
data = dict(res['rows'][0])
SQL = render_template(
"/".join([self.template_path, 'delete.sql']),
data=data, conn=self.conn, cascade=cascade
)
status, res = self.conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("Index is dropped"), info=gettext("Index is dropped")
data={
'id': idx,
'tid': tid
}
) )
except Exception as e: except Exception as e:

View File

@ -0,0 +1,98 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import uuid
import json
from pgadmin.browser.server_groups.servers.databases.schemas.tables.column. \
tests import utils as columns_utils
from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
import utils as tables_utils
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 . import utils as indexes_utils
class IndexesDeleteMultipleTestCase(BaseTestGenerator):
"""This class will delete the existing index of column."""
scenarios = [
('Delete index Node URL', dict(url='/browser/index/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_column_%s" % (str(uuid.uuid4())[1:8])
self.table_id = tables_utils.create_table(self.server, self.db_name,
self.schema_name,
self.table_name)
self.column_name = "test_column_delete_%s" % (str(uuid.uuid4())[1:8])
self.column_id = columns_utils.create_column(self.server,
self.db_name,
self.schema_name,
self.table_name,
self.column_name)
self.index_name = "test_index_delete_%s" % (str(uuid.uuid4())[1:8])
self.index_name_1 = "test_index_delete_%s" % (str(uuid.uuid4())[1:8])
self.index_ids = [indexes_utils.create_index(self.server, self.db_name,
self.schema_name,
self.table_name,
self.index_name,
self.column_name),
indexes_utils.create_index(self.server, self.db_name,
self.schema_name,
self.table_name,
self.index_name_1,
self.column_name)
]
def runTest(self):
"""This function will delete index of existing column."""
index_response = indexes_utils.verify_index(self.server, self.db_name,
self.index_name)
if not index_response:
raise Exception("Could not find the index to delete.")
index_response = indexes_utils.verify_index(self.server, self.db_name,
self.index_name_1)
if not index_response:
raise Exception("Could not find the index to delete.")
data = {'ids': self.index_ids}
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)

View File

@ -163,12 +163,12 @@ class RuleView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'children': [{ 'children': [{
'get': 'children' 'get': 'children'
}], }],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
'msql': [{'get': 'msql'}, {'get': 'msql'}], 'msql': [{'get': 'msql'}, {'get': 'msql'}],
@ -382,54 +382,56 @@ class RuleView(PGChildNodeView):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, tid, rid): def delete(self, gid, sid, did, scid, tid, rid=None):
""" """
This function will drop a rule object This function will drop a rule object
""" """
if rid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [rid]}
# Below will decide if it's simple drop or drop with cascade call # Below will decide if it's simple drop or drop with cascade call
cascade = True if self.cmd == 'delete' else False cascade = True if self.cmd == 'delete' else False
try: try:
# Get name for rule from did for rid in data['ids']:
SQL = render_template("/".join( # Get name for rule from did
[self.template_path, 'delete.sql']), rid=rid) SQL = render_template("/".join(
status, res_data = self.conn.execute_dict(SQL) [self.template_path, 'delete.sql']), rid=rid)
if not status: status, res_data = self.conn.execute_dict(SQL)
return internal_server_error(errormsg=res_data) if not status:
return internal_server_error(errormsg=res_data)
if not res_data['rows']: if not res_data['rows']:
return make_json_response( return make_json_response(
success=0, success=0,
errormsg=gettext( errormsg=gettext(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=gettext( info=gettext(
'The specified rule could not be found.\n' 'The specified rule could not be found.\n'
)
) )
)
# drop rule # drop rule
rset = res_data['rows'][0] rset = res_data['rows'][0]
SQL = render_template("/".join( SQL = render_template("/".join(
[self.template_path, 'delete.sql']), [self.template_path, 'delete.sql']),
rulename=rset['rulename'], rulename=rset['rulename'],
relname=rset['relname'], relname=rset['relname'],
nspname=rset['nspname'], nspname=rset['nspname'],
cascade=cascade cascade=cascade
) )
status, res = self.conn.execute_scalar(SQL) status, res = self.conn.execute_scalar(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("Rule dropped"), info=gettext("Rule dropped")
data={
'id': tid,
'sid': sid,
'gid': gid,
'did': did
}
) )
except Exception as e: except Exception as e:

View File

@ -0,0 +1,89 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import uuid
import json
from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
import utils as tables_utils
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 . import utils as rules_utils
class RulesDeleteTestCase(BaseTestGenerator):
"""This class will delete rule under table node."""
scenarios = [
('Delete rule Node URL', dict(url='/browser/rule/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 delete rule.")
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 delete rule.")
self.table_name = "table_column_%s" % (str(uuid.uuid4())[1:8])
self.table_id = tables_utils.create_table(self.server, self.db_name,
self.schema_name,
self.table_name)
self.rule_name = "test_rule_delete_%s" % (str(uuid.uuid4())[1:8])
self.rule_name_1 = "test_rule_delete_%s" % (str(uuid.uuid4())[1:8])
self.rule_ids = [rules_utils.create_rule(self.server, self.db_name,
self.schema_name,
self.table_name,
self.rule_name),
rules_utils.create_rule(self.server, self.db_name,
self.schema_name,
self.table_name,
self.rule_name_1),
]
def runTest(self):
"""This function will delete rule under table node."""
rule_response = rules_utils.verify_rule(self.server, self.db_name,
self.rule_name)
if not rule_response:
raise Exception("Could not find the rule to delete.")
rule_response = rules_utils.verify_rule(self.server, self.db_name,
self.rule_name_1)
if not rule_response:
raise Exception("Could not find the rule to delete.")
data = {'ids': self.rule_ids}
response = self.tester.delete(
"{0}{1}/{2}/{3}/{4}/{5}/".format(self.url, utils.SERVER_GROUP,
self.server_id, self.db_id,
self.schema_id, self.table_id
),
follow_redirects=True,
data=json.dumps(data),
content_type='html/json'
)
self.assertEquals(response.status_code, 200)
def tearDown(self):
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)

View File

@ -228,6 +228,7 @@ define('pgadmin.node.table_partition_utils', [
}); });
Backform.PartitionsModel = pgBrowser.Node.Model.extend({ Backform.PartitionsModel = pgBrowser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
oid: undefined, oid: undefined,
is_attach: false, is_attach: false,

View File

@ -263,6 +263,7 @@ define('pgadmin.node.table', [
}, },
}, },
model: pgBrowser.Node.Model.extend({ model: pgBrowser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, name: undefined,
oid: undefined, oid: undefined,

View File

@ -0,0 +1,80 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, 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 . import utils as tables_utils
class TableDeleteMultipleTestCase(BaseTestGenerator):
"""This class will delete new table under schema node."""
scenarios = [
# Fetching default URL for table node.
('Delete Table', dict(url='/browser/table/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 = "test_table_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)
self.table_name_1 = "test_table_delete_%s" % (str(uuid.uuid4())[1:8])
self.table_id_1 = tables_utils.create_table(self.server, self.db_name,
self.schema_name,
self.table_name_1
)
def runTest(self):
"""This function will delete added table under schema node."""
table_response = tables_utils.verify_table(self.server, self.db_name,
self.table_id)
if not table_response:
raise Exception("Could not find the table to delete.")
table_response = tables_utils.verify_table(self.server, self.db_name,
self.table_id_1)
if not table_response:
raise Exception("Could not find the table to delete.")
data = {'ids': [self.table_id, self.table_id_1]}
response = self.tester.delete(self.url + str(utils.SERVER_GROUP) +
'/' + str(self.server_id) + '/' +
str(self.db_id) + '/' +
str(self.schema_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)

View File

@ -238,9 +238,9 @@ class TriggerView(PGChildNodeView):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -671,7 +671,7 @@ class TriggerView(PGChildNodeView):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, tid, trid): def delete(self, gid, sid, did, scid, tid, trid=None):
""" """
This function will updates existing the trigger object This function will updates existing the trigger object
@ -683,6 +683,13 @@ class TriggerView(PGChildNodeView):
tid: Table ID tid: Table ID
trid: Trigger ID trid: Trigger ID
""" """
if trid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [trid]}
# Below will decide if it's simple drop or drop with cascade call # Below will decide if it's simple drop or drop with cascade call
if self.cmd == 'delete': if self.cmd == 'delete':
# This is a cascade operation # This is a cascade operation
@ -691,44 +698,44 @@ class TriggerView(PGChildNodeView):
cascade = False cascade = False
try: try:
# We will first fetch the trigger name for current request for trid in data['ids']:
# so that we create template for dropping trigger # We will first fetch the trigger name for current request
SQL = render_template("/".join([self.template_path, # so that we create template for dropping trigger
'properties.sql']), SQL = render_template("/".join([self.template_path,
tid=tid, trid=trid, 'properties.sql']),
datlastsysoid=self.datlastsysoid) tid=tid, trid=trid,
datlastsysoid=self.datlastsysoid)
status, res = self.conn.execute_dict(SQL) status, res = self.conn.execute_dict(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return internal_server_error(errormsg=res)
if not res['rows']: if not res['rows']:
return make_json_response( return make_json_response(
success=0, success=0,
errormsg=gettext( errormsg=gettext(
'Error: Object not found.' 'Error: Object not found.'
), ),
info=gettext( info=gettext(
'The specified trigger could not be found.\n' 'The specified trigger could not be found.\n'
)
) )
)
data = dict(res['rows'][0]) data = dict(res['rows'][0])
SQL = render_template("/".join([self.template_path, SQL = render_template("/".join([self.template_path,
'delete.sql']), 'delete.sql']),
data=data, conn=self.conn, cascade=cascade) data=data,
status, res = self.conn.execute_scalar(SQL) conn=self.conn,
if not status: cascade=cascade
return internal_server_error(errormsg=res) )
status, res = self.conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("Trigger is dropped"), info=gettext("Trigger is dropped")
data={
'id': trid,
'tid': tid
}
) )
except Exception as e: except Exception as e:

View File

@ -181,6 +181,7 @@ define('pgadmin.node.trigger', [
canDrop: SchemaChildTreeNode.isTreeItemOfChildOfSchema, canDrop: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
canDropCascade: SchemaChildTreeNode.isTreeItemOfChildOfSchema, canDropCascade: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
model: pgAdmin.Browser.Node.Model.extend({ model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid',
defaults: { defaults: {
name: undefined, name: undefined,
is_row_trigger: true, is_row_trigger: true,

View File

@ -0,0 +1,103 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import uuid
import json
from pgadmin.browser.server_groups.servers.databases.schemas.functions.tests \
import utils as trigger_funcs_utils
from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
import utils as tables_utils
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 . import utils as triggers_utils
class TriggersDeleteTestCase(BaseTestGenerator):
"""This class will delete trigger under table node."""
skip_on_database = ['gpdb']
scenarios = [
('Delete trigger Node URL', dict(url='/browser/trigger/obj/'))
]
def setUp(self):
super(TriggersDeleteTestCase, self).setUp()
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 delete trigger.")
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 delete trigger.")
self.table_name = "table_trigger_%s" % (str(uuid.uuid4())[1:8])
self.table_id = tables_utils.create_table(self.server, self.db_name,
self.schema_name,
self.table_name)
self.func_name = "trigger_func_delete_%s" % str(uuid.uuid4())[1:8]
self.function_info = \
trigger_funcs_utils.create_trigger_function_with_trigger(
self.server, self.db_name, self.schema_name, self.func_name)
self.trigger_name = "test_trigger_delete_%s" % (str(uuid.uuid4())[1:8])
self.trigger_name_1 = "test_trigger_delete_%s" %\
(str(uuid.uuid4())[1:8])
self.trigger_ids = [triggers_utils.create_trigger(self.server,
self.db_name,
self.schema_name,
self.table_name,
self.trigger_name,
self.func_name),
triggers_utils.create_trigger(self.server,
self.db_name,
self.schema_name,
self.table_name,
self.trigger_name_1,
self.func_name)
]
def runTest(self):
"""This function will delete trigger under table node."""
trigger_response = triggers_utils.verify_trigger(self.server,
self.db_name,
self.trigger_name)
if not trigger_response:
raise Exception("Could not find the trigger to delete.")
trigger_response = triggers_utils.verify_trigger(self.server,
self.db_name,
self.trigger_name_1)
if not trigger_response:
raise Exception("Could not find the trigger to delete.")
data = {'ids': self.trigger_ids}
response = self.tester.delete(
"{0}{1}/{2}/{3}/{4}/{5}/".format(self.url, utils.SERVER_GROUP,
self.server_id, self.db_id,
self.schema_id, self.table_id
),
follow_redirects=True,
data=json.dumps(data),
content_type='html/json'
)
self.assertEquals(response.status_code, 200)
def tearDown(self):
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)

View File

@ -2363,16 +2363,12 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
) )
status, res = self.conn.execute_scalar(SQL) status, res = self.conn.execute_scalar(SQL)
if not status: if not status:
return internal_server_error(errormsg=res) return status, res
return make_json_response( return True, {
success=1, 'id': tid,
info=gettext("Table dropped"), 'scid': scid
data={ }
'id': tid,
'scid': scid
}
)
def get_schema_and_table_name(self, tid): def get_schema_and_table_name(self, tid):
""" """

View File

@ -0,0 +1,88 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import uuid
import json
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 . import utils as schema_utils
class SchemaDeleteMultipleTestCase(BaseTestGenerator):
""" This class will add new schema under database node. """
scenarios = [
# Fetching default URL for extension node.
('Check Schema Node URL', dict(url='/browser/schema/obj/'))
]
def setUp(self):
self.database_info = parent_node_dict["database"][-1]
self.db_name = self.database_info["db_name"]
# Change the db name, so that schema will create in newly created db
self.schema_names = ["schema_get_%s" % str(uuid.uuid4())[1:8],
"schema_get_%s" % str(uuid.uuid4())[1:8]]
connection = utils.get_db_connection(self.db_name,
self.server['username'],
self.server['db_password'],
self.server['host'],
self.server['port'])
self.schema_details = schema_utils.create_schema(connection,
self.schema_names[0])
connection = utils.get_db_connection(self.db_name,
self.server['username'],
self.server['db_password'],
self.server['host'],
self.server['port'])
self.schema_details_1 = schema_utils.create_schema(
connection,
self.schema_names[1]
)
def runTest(self):
""" This function will delete schema under database node. """
server_id = self.database_info["server_id"]
db_id = self.database_info["db_id"]
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
server_id, db_id)
if not db_con['data']["connected"]:
raise Exception("Could not connect to database to delete the"
" schema.")
schema_id = self.schema_details[0]
schema_name = self.schema_details[1]
schema_response = schema_utils.verify_schemas(self.server,
self.db_name,
schema_name)
if not schema_response:
raise Exception("Could not find the schema to delete.")
schema_id = self.schema_details_1[0]
schema_name = self.schema_details_1[1]
schema_response = schema_utils.verify_schemas(self.server,
self.db_name,
schema_name)
if not schema_response:
raise Exception("Could not find the schema to delete.")
data = {'ids': [self.schema_details[0], self.schema_details_1[0]]}
response = self.tester.delete(self.url + str(utils.SERVER_GROUP) +
'/' + str(server_id) + '/' +
str(db_id),
follow_redirects=True,
data=json.dumps(data),
content_type='html/json')
self.assertEquals(response.status_code, 200)
def tearDown(self):
pass

View File

@ -190,9 +190,9 @@ class TypeView(PGChildNodeView, DataTypeReader):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'children': [{'get': 'children'}], 'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
@ -1063,7 +1063,7 @@ class TypeView(PGChildNodeView, DataTypeReader):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, tid): def delete(self, gid, sid, did, scid, tid=None):
""" """
This function will updates existing the type object This function will updates existing the type object
@ -1074,6 +1074,12 @@ class TypeView(PGChildNodeView, DataTypeReader):
scid: Schema ID scid: Schema ID
tid: Type ID tid: Type ID
""" """
if tid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [tid]}
# Below will decide if it's simple drop or drop with cascade call # Below will decide if it's simple drop or drop with cascade call
if self.cmd == 'delete': if self.cmd == 'delete':
@ -1083,37 +1089,40 @@ class TypeView(PGChildNodeView, DataTypeReader):
cascade = False cascade = False
try: try:
for tid in data['ids']:
SQL = render_template( SQL = render_template(
"/".join([self.template_path, "/".join([self.template_path,
'properties.sql']), 'properties.sql']),
scid=scid, tid=tid, scid=scid, tid=tid,
datlastsysoid=self.datlastsysoid, datlastsysoid=self.datlastsysoid,
show_system_objects=self.blueprint.show_system_objects show_system_objects=self.blueprint.show_system_objects
)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if not res['rows']:
return make_json_response(
success=0,
errormsg=gettext(
'Error: Object not found.'
),
info=gettext(
'The specified type could not be found.\n'
)
) )
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
# Making copy of output for future use if not res['rows']:
data = dict(res['rows'][0]) return make_json_response(
success=0,
errormsg=gettext(
'Error: Object not found.'
),
info=gettext(
'The specified type could not be found.\n'
)
)
SQL = render_template("/".join([self.template_path, 'delete.sql']), # Making copy of output for future use
data=data, cascade=cascade, conn=self.conn) data = dict(res['rows'][0])
status, res = self.conn.execute_scalar(SQL)
if not status: SQL = render_template("/".join([self.template_path,
return internal_server_error(errormsg=res) 'delete.sql']),
data=data,
cascade=cascade,
conn=self.conn)
status, res = self.conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,

View File

@ -270,12 +270,12 @@ class ViewNode(PGChildNodeView, VacuumSettings):
operations = dict({ operations = dict({
'obj': [ 'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'}, {'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'} {'get': 'list', 'post': 'create', 'delete': 'delete'}
], ],
'children': [{ 'children': [{
'get': 'children' 'get': 'children'
}], }],
'delete': [{'delete': 'delete'}], 'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}], 'sql': [{'get': 'sql'}],
'msql': [{'get': 'msql'}, {'get': 'msql'}], 'msql': [{'get': 'msql'}, {'get': 'msql'}],
@ -557,60 +557,61 @@ class ViewNode(PGChildNodeView, VacuumSettings):
return internal_server_error(errormsg=str(e)) return internal_server_error(errormsg=str(e))
@check_precondition @check_precondition
def delete(self, gid, sid, did, scid, vid): def delete(self, gid, sid, did, scid, vid=None):
""" """
This function will drop a view object This function will drop a view object
""" """
if vid is None:
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
else:
data = {'ids': [vid]}
# Below will decide if it's simple drop or drop with cascade call # Below will decide if it's simple drop or drop with cascade call
cascade = True if self.cmd == 'delete' else False cascade = True if self.cmd == 'delete' else False
try: try:
# Get name for view from vid for vid in data['ids']:
SQL = render_template( # Get name for view from vid
"/".join([ SQL = render_template(
self.template_path, 'sql/properties.sql' "/".join([
]), self.template_path, 'sql/properties.sql'
did=did, ]),
vid=vid, did=did,
datlastsysoid=self.datlastsysoid vid=vid,
) datlastsysoid=self.datlastsysoid
status, res_data = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res_data)
if not res_data['rows']:
return make_json_response(
success=0,
errormsg=gettext(
'Error: Object not found.'
),
info=gettext(
'The specified view could not be found.\n'
)
) )
status, res_data = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res_data)
# drop view if not res_data['rows']:
SQL = render_template( return make_json_response(
"/".join([ success=0,
self.template_path, 'sql/delete.sql' errormsg=gettext(
]), 'Error: Object not found.'
nspname=res_data['rows'][0]['schema'], ),
name=res_data['rows'][0]['name'], cascade=cascade info=gettext(
) 'The specified view could not be found.\n'
status, res = self.conn.execute_scalar(SQL) )
if not status: )
return internal_server_error(errormsg=res)
# drop view
SQL = render_template(
"/".join([
self.template_path, 'sql/delete.sql'
]),
nspname=res_data['rows'][0]['schema'],
name=res_data['rows'][0]['name'], cascade=cascade
)
status, res = self.conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=res)
return make_json_response( return make_json_response(
success=1, success=1,
info=gettext("View dropped"), info=gettext("View dropped")
data={
'id': vid,
'sid': sid,
'gid': gid,
'did': did
}
) )
except Exception as e: except Exception as e:

View File

@ -115,6 +115,7 @@ define('pgadmin.node.mview', [
properties of the model in schema. properties of the model in schema.
*/ */
model: pgBrowser.Node.Model.extend({ model: pgBrowser.Node.Model.extend({
idAttribute: 'oid',
initialize: function(attrs, args) { initialize: function(attrs, args) {
if (_.size(attrs) === 0) { if (_.size(attrs) === 0) {
// Set Selected Schema and Current User // Set Selected Schema and Current User

View File

@ -85,6 +85,7 @@ define('pgadmin.node.view', [
properties of the model in schema. properties of the model in schema.
*/ */
model: pgBrowser.Node.Model.extend({ model: pgBrowser.Node.Model.extend({
idAttribute: 'oid',
initialize: function(attrs, args) { initialize: function(attrs, args) {
if (_.size(attrs) === 0) { if (_.size(attrs) === 0) {
// Set Selected Schema and, Current User // Set Selected Schema and, Current User

View File

@ -0,0 +1,104 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2018, 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 import server_utils as server_utils
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as views_utils
class ViewsDeleteMultipleTestCase(BaseTestGenerator):
"""This class will delete the view/mview under schema node."""
view_sql = "CREATE OR REPLACE VIEW %s.%s AS SELECT 'Hello World'; " \
"ALTER TABLE %s.%s OWNER TO %s"
m_view_sql = "CREATE MATERIALIZED VIEW %s.%s TABLESPACE pg_default AS " \
"SELECT 'test_pgadmin' WITH NO DATA;ALTER TABLE %s.%s OWNER" \
" TO %s"
scenarios = [
('Delete multiple view under schema node', dict(
url='/browser/view/obj/',
view_name=["test_view_delete_%s" % (str(uuid.uuid4())[1:8]),
"test_view_delete_%s" % (str(uuid.uuid4())[1:8])],
sql_query=view_sql)),
('Delete multiple materialized view under schema node',
dict(url='/browser/mview/obj/',
view_name=["test_mview_delete_%s" % (str(uuid.uuid4())[1:8]),
"test_mview_delete_%s" % (str(uuid.uuid4())[1:8])],
sql_query=m_view_sql))
]
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"]
server_response = server_utils.connect_server(self, self.server_id)
if server_response["data"]["version"] < 90300 and "mview" in self.url:
message = "Materialized Views are not supported by PG9.2 " \
"and PPAS9.2 and below."
self.skipTest(message)
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 delete view.")
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 delete the view.")
self.view_ids = [views_utils.create_view(self.server,
self.db_name,
self.schema_name,
self.sql_query,
self.view_name[0]),
views_utils.create_view(self.server,
self.db_name,
self.schema_name,
self.sql_query,
self.view_name[1])
]
def runTest(self):
"""This function will delete the view/mview under schema node."""
view_response = views_utils.verify_view(self.server, self.db_name,
self.view_name[0])
if not view_response:
raise Exception("Could not find the view to delete.")
view_response = views_utils.verify_view(self.server, self.db_name,
self.view_name[1])
if not view_response:
raise Exception("Could not find the view to delete.")
data = {'ids': self.view_ids}
response = self.tester.delete(
"{0}{1}/{2}/{3}/{4}/".format(self.url, utils.SERVER_GROUP,
self.server_id, self.db_id,
self.schema_id
),
follow_redirects=True,
data=json.dumps(data),
content_type='html/json'
)
self.assertEquals(response.status_code, 200)
def tearDown(self):
# Disconnect the database
database_utils.disconnect_database(self, self.server_id, self.db_id)

View File

@ -13,6 +13,8 @@ define('pgadmin.node.database', [
type: 'coll-database', type: 'coll-database',
columns: ['name', 'datowner', 'comments'], columns: ['name', 'datowner', 'comments'],
hasStatistics: true, hasStatistics: true,
canDrop: true,
canDropCascade: false,
statsPrettifyFields: ['Size', 'Size of temporary files'], statsPrettifyFields: ['Size', 'Size of temporary files'],
}); });
} }
@ -257,6 +259,7 @@ define('pgadmin.node.database', [
}, },
}, },
model: pgBrowser.Node.Model.extend({ model: pgBrowser.Node.Model.extend({
idAttribute: 'did',
defaults: { defaults: {
name: undefined, name: undefined,
owner: undefined, owner: undefined,

Some files were not shown because too many files have changed in this diff Show More