Add support for displaying dependency and dependents info.
parent
0b956813d4
commit
c153032e3b
|
@ -22,6 +22,7 @@ from config import PG_DEFAULT_DRIVER
|
|||
from functools import wraps
|
||||
import re
|
||||
|
||||
|
||||
class DatabaseModule(CollectionNodeModule):
|
||||
NODE_TYPE = 'database'
|
||||
COLLECTION_LABEL = _("Databases")
|
||||
|
@ -853,4 +854,38 @@ class DatabaseView(PGChildNodeView):
|
|||
|
||||
return ajax_response(response=SQL)
|
||||
|
||||
@check_precondition()
|
||||
def dependents(self, gid, sid, did):
|
||||
"""
|
||||
This function gets the dependents and returns an ajax response
|
||||
for the database.
|
||||
|
||||
Args:
|
||||
gid: Server Group ID
|
||||
sid: Server ID
|
||||
did: Database ID
|
||||
"""
|
||||
dependents_result = self.get_dependents(self.conn, did)
|
||||
return ajax_response(
|
||||
response=dependents_result,
|
||||
status=200
|
||||
)
|
||||
|
||||
@check_precondition()
|
||||
def dependencies(self, gid, sid, did):
|
||||
"""
|
||||
This function gets the dependencies and returns an ajax response
|
||||
for the database.
|
||||
|
||||
Args:
|
||||
gid: Server Group ID
|
||||
sid: Server ID
|
||||
did: Database ID
|
||||
"""
|
||||
dependencies_result = self.get_dependencies(self.conn, did)
|
||||
return ajax_response(
|
||||
response=dependencies_result,
|
||||
status=200
|
||||
)
|
||||
|
||||
DatabaseView.register_node_view(blueprint)
|
||||
|
|
|
@ -46,6 +46,7 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
|
|||
parent_type: 'server',
|
||||
type: 'database',
|
||||
hasSQL: true,
|
||||
hasDepends: true,
|
||||
canDrop: true,
|
||||
label: '{{ _('Database') }}',
|
||||
node_image: function() {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
from flask import render_template, request, jsonify
|
||||
from flask import render_template, request, jsonify, current_app
|
||||
from flask.ext.babel import gettext as _
|
||||
from pgadmin.utils.ajax import make_json_response, \
|
||||
make_response as ajax_response, precondition_required, \
|
||||
|
@ -822,11 +822,149 @@ rolmembership:{
|
|||
|
||||
@check_precondition()
|
||||
def dependencies(self, gid, sid, rid):
|
||||
return not_implemented()
|
||||
"""
|
||||
This function gets the dependencies and returns an ajax response
|
||||
for the role.
|
||||
|
||||
Args:
|
||||
gid: Server Group ID
|
||||
sid: Server ID
|
||||
rid: Role ID
|
||||
"""
|
||||
dependencies_result = self.get_dependencies(self.conn, rid)
|
||||
return ajax_response(
|
||||
response=dependencies_result,
|
||||
status=200
|
||||
)
|
||||
|
||||
@check_precondition()
|
||||
def dependents(self, gid, sid, rid):
|
||||
return not_implemented()
|
||||
"""
|
||||
This function gets the dependents and returns an ajax response
|
||||
for the role.
|
||||
|
||||
Args:
|
||||
gid: Server Group ID
|
||||
sid: Server ID
|
||||
rid: Role ID
|
||||
"""
|
||||
dependents_result = self.get_dependents(self.conn, sid, rid)
|
||||
return ajax_response(
|
||||
response=dependents_result,
|
||||
status=200
|
||||
)
|
||||
|
||||
def get_dependents(self, conn, sid, rid):
|
||||
"""
|
||||
This function is used to fetch the dependents for the selected node.
|
||||
|
||||
Args:
|
||||
conn: Connection object
|
||||
sid: Server Id
|
||||
rid: Role Id.
|
||||
|
||||
Returns: Dictionary of dependents for the selected node.
|
||||
"""
|
||||
|
||||
# Dictionary for the object types
|
||||
types = {
|
||||
# None specified special handling for this type
|
||||
'r': 'table',
|
||||
'i': None,
|
||||
'S': 'sequence',
|
||||
'v': 'view',
|
||||
'x': 'external_table',
|
||||
'p': 'function',
|
||||
'n': 'schema',
|
||||
'y': 'type',
|
||||
'd': 'domain',
|
||||
'T': 'trigger_function',
|
||||
'C': 'conversion',
|
||||
'o': None
|
||||
}
|
||||
|
||||
query = render_template("/".join([self.sql_path, 'dependents.sql']),
|
||||
fetch_database=True, rid=rid)
|
||||
status, db_result = self.conn.execute_dict(query)
|
||||
if not status:
|
||||
current_app.logger.error(db_result)
|
||||
|
||||
dependents = list()
|
||||
|
||||
# Get the server manager
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
|
||||
|
||||
for db_row in db_result['rows']:
|
||||
oid = db_row['datdba']
|
||||
if db_row['type'] == 'd':
|
||||
if rid == oid:
|
||||
dependents.append({'type': 'database', 'name': '', 'field': db_row['datname']})
|
||||
else:
|
||||
dependents.append({'type': 'tablespace', 'name': db_row['datname'], 'field': ''})
|
||||
|
||||
# If connection to the database is not allowed then continue
|
||||
# with the next database
|
||||
if not db_row['datallowconn']:
|
||||
continue
|
||||
|
||||
# Get the connection from the manager for the specified database.
|
||||
# Check the connect status and if it is not connected then create
|
||||
# a new connection to run the query and fetch the dependents.
|
||||
is_connected = True
|
||||
try:
|
||||
temp_conn = manager.connection(db_row['datname'])
|
||||
is_connected = temp_conn.connected()
|
||||
if not is_connected:
|
||||
temp_conn.connect()
|
||||
except Exception as e:
|
||||
current_app.logger.exception(e)
|
||||
|
||||
if temp_conn.connected():
|
||||
query = render_template("/".join([self.sql_path, 'dependents.sql']),
|
||||
fetch_dependents=True, rid=rid, lastsysoid=db_row['datlastsysoid'])
|
||||
|
||||
status, result = temp_conn.execute_dict(query)
|
||||
if not status:
|
||||
current_app.logger.error(result)
|
||||
|
||||
for row in result['rows']:
|
||||
rel_name = row['nspname']
|
||||
if rel_name is not None:
|
||||
rel_name += '.'
|
||||
|
||||
if rel_name is None:
|
||||
rel_name = row['relname']
|
||||
else:
|
||||
rel_name += row['relname']
|
||||
|
||||
type_name = ''
|
||||
type_str = row['relkind']
|
||||
# Fetch the type name from the dictionary
|
||||
# if type is not present in the types dictionary then
|
||||
# we will continue and not going to add it.
|
||||
if type_str[0] in types:
|
||||
|
||||
# if type is present in the types dictionary, but it's
|
||||
# value is None then it requires special handling.
|
||||
if types[type_str[0]] is None:
|
||||
if type_str[0] == 'i':
|
||||
type_name = 'index'
|
||||
rel_name = row['indname'] + ' ON ' + rel_name
|
||||
elif type_str[0] == 'o':
|
||||
type_name = 'operator'
|
||||
rel_name = row['relname']
|
||||
else:
|
||||
type_name = types[type_str[0]]
|
||||
else:
|
||||
continue
|
||||
|
||||
dependents.append({'type': type_name, 'name': rel_name, 'field': db_row['datname']})
|
||||
|
||||
# Release only those connections which we have created above.
|
||||
if not is_connected:
|
||||
manager.release(db_row['datname'])
|
||||
|
||||
return dependents
|
||||
|
||||
@check_precondition()
|
||||
def variables(self, gid, sid, rid):
|
||||
|
|
|
@ -293,10 +293,13 @@ function($, _, S, pgAdmin, pgBrowser, alertify, Backform) {
|
|||
label: '{{ _('Login/Group Role') }}',
|
||||
hasSQL: true,
|
||||
canDrop: true,
|
||||
hasDepends: true,
|
||||
node_label: function(r) {
|
||||
return r.label;
|
||||
},
|
||||
node_image: function(r) {
|
||||
if (r == null || r == undefined)
|
||||
return 'icon-role';
|
||||
return (r.can_login ? 'icon-role' : 'icon-group');
|
||||
},
|
||||
title: function(d) {
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
{% if fetch_database %}
|
||||
SELECT 'd' as type, datname,
|
||||
datallowconn AND pg_catalog.has_database_privilege(datname, 'CONNECT') AS datallowconn,
|
||||
datdba, datlastsysoid
|
||||
FROM pg_database db
|
||||
UNION
|
||||
SELECT 'M', spcname, null, null, null
|
||||
FROM pg_tablespace where spcowner= {{rid}}::int
|
||||
ORDER BY 1, 2
|
||||
{% endif %}
|
||||
|
||||
{% if fetch_dependents %}
|
||||
SELECT cl.relkind, COALESCE(cin.nspname, cln.nspname) as nspname,
|
||||
COALESCE(ci.relname, cl.relname) as relname, cl.relname as indname
|
||||
FROM pg_class cl
|
||||
JOIN pg_namespace cln ON cl.relnamespace=cln.oid
|
||||
LEFT OUTER JOIN pg_index ind ON ind.indexrelid=cl.oid
|
||||
LEFT OUTER JOIN pg_class ci ON ind.indrelid=ci.oid
|
||||
LEFT OUTER JOIN pg_namespace cin ON ci.relnamespace=cin.oid
|
||||
WHERE cl.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND cl.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT 'n', null, nspname, null
|
||||
FROM pg_namespace nsp
|
||||
WHERE nsp.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND nsp.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT CASE WHEN typtype='d' THEN 'd' ELSE 'y' END, null, typname, null
|
||||
FROM pg_type ty
|
||||
WHERE ty.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND ty.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT 'C', null, conname, null
|
||||
FROM pg_conversion co
|
||||
WHERE co.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND co.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT CASE WHEN prorettype=2279 THEN 'T' ELSE 'p' END, null, proname, null
|
||||
FROM pg_proc pr
|
||||
WHERE pr.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND pr.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT 'o', null, oprname || '('::text || COALESCE(tl.typname, ''::text) || CASE WHEN tl.oid IS NOT NULL
|
||||
AND tr.oid IS NOT NULL THEN ','::text END || COALESCE(tr.typname, ''::text) || ')'::text, null
|
||||
FROM pg_operator op
|
||||
LEFT JOIN pg_type tl ON tl.oid=op.oprleft
|
||||
LEFT JOIN pg_type tr ON tr.oid=op.oprright
|
||||
WHERE op.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND op.oid > {{lastsysoid}}::int
|
||||
ORDER BY 1,2,3
|
||||
{% endif %}
|
|
@ -0,0 +1,40 @@
|
|||
{% if fetch_database %}
|
||||
SELECT 'd' as type, datname,
|
||||
datallowconn AND pg_catalog.has_database_privilege(datname, 'CONNECT') AS datallowconn,
|
||||
datdba, datlastsysoid
|
||||
FROM pg_database db
|
||||
UNION
|
||||
SELECT 'M', spcname, null, null, null
|
||||
FROM pg_tablespace where spcowner= {{rid}}::int
|
||||
ORDER BY 1, 2
|
||||
{% endif %}
|
||||
|
||||
{% if fetch_dependents %}
|
||||
SELECT cl.relkind, COALESCE(cin.nspname, cln.nspname) as nspname,
|
||||
COALESCE(ci.relname, cl.relname) as relname, cl.relname as indname
|
||||
FROM pg_class cl
|
||||
JOIN pg_namespace cln ON cl.relnamespace=cln.oid
|
||||
LEFT OUTER JOIN pg_index ind ON ind.indexrelid=cl.oid
|
||||
LEFT OUTER JOIN pg_class ci ON ind.indrelid=ci.oid
|
||||
LEFT OUTER JOIN pg_namespace cin ON ci.relnamespace=cin.oid
|
||||
WHERE cl.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND cl.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT 'n', null, nspname, null
|
||||
FROM pg_namespace nsp
|
||||
WHERE nsp.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND nsp.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT CASE WHEN typtype='d' THEN 'd' ELSE 'y' END, null, typname, null
|
||||
FROM pg_type ty
|
||||
WHERE ty.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND ty.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT 'C', null, conname, null
|
||||
FROM pg_conversion co
|
||||
WHERE co.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND co.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT CASE WHEN prorettype=2279 THEN 'T' ELSE 'p' END, null, proname, null
|
||||
FROM pg_proc pr
|
||||
WHERE pr.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND pr.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT 'o', null, oprname || '('::text || COALESCE(tl.typname, ''::text) || CASE WHEN tl.oid IS NOT NULL
|
||||
AND tr.oid IS NOT NULL THEN ','::text END || COALESCE(tr.typname, ''::text) || ')'::text, null
|
||||
FROM pg_operator op
|
||||
LEFT JOIN pg_type tl ON tl.oid=op.oprleft
|
||||
LEFT JOIN pg_type tr ON tr.oid=op.oprright
|
||||
WHERE op.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND op.oid > {{lastsysoid}}::int
|
||||
ORDER BY 1,2,3
|
||||
{% endif %}
|
|
@ -0,0 +1,40 @@
|
|||
{% if fetch_database %}
|
||||
SELECT 'd' as type, datname,
|
||||
datallowconn AND pg_catalog.has_database_privilege(datname, 'CONNECT') AS datallowconn,
|
||||
datdba, datlastsysoid
|
||||
FROM pg_database db
|
||||
UNION
|
||||
SELECT 'M', spcname, null, null, null
|
||||
FROM pg_tablespace where spcowner= {{rid}}::int
|
||||
ORDER BY 1, 2
|
||||
{% endif %}
|
||||
|
||||
{% if fetch_dependents %}
|
||||
SELECT cl.relkind, COALESCE(cin.nspname, cln.nspname) as nspname,
|
||||
COALESCE(ci.relname, cl.relname) as relname, cl.relname as indname
|
||||
FROM pg_class cl
|
||||
JOIN pg_namespace cln ON cl.relnamespace=cln.oid
|
||||
LEFT OUTER JOIN pg_index ind ON ind.indexrelid=cl.oid
|
||||
LEFT OUTER JOIN pg_class ci ON ind.indrelid=ci.oid
|
||||
LEFT OUTER JOIN pg_namespace cin ON ci.relnamespace=cin.oid
|
||||
WHERE cl.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND cl.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT 'n', null, nspname, null
|
||||
FROM pg_namespace nsp
|
||||
WHERE nsp.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND nsp.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT CASE WHEN typtype='d' THEN 'd' ELSE 'y' END, null, typname, null
|
||||
FROM pg_type ty
|
||||
WHERE ty.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND ty.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT 'C', null, conname, null
|
||||
FROM pg_conversion co
|
||||
WHERE co.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND co.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT CASE WHEN prorettype=2279 THEN 'T' ELSE 'p' END, null, proname, null
|
||||
FROM pg_proc pr
|
||||
WHERE pr.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND pr.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT 'o', null, oprname || '('::text || COALESCE(tl.typname, ''::text) || CASE WHEN tl.oid IS NOT NULL
|
||||
AND tr.oid IS NOT NULL THEN ','::text END || COALESCE(tr.typname, ''::text) || ')'::text, null
|
||||
FROM pg_operator op
|
||||
LEFT JOIN pg_type tl ON tl.oid=op.oprleft
|
||||
LEFT JOIN pg_type tr ON tr.oid=op.oprright
|
||||
WHERE op.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND op.oid > {{lastsysoid}}::int
|
||||
ORDER BY 1,2,3
|
||||
{% endif %}
|
|
@ -0,0 +1,40 @@
|
|||
{% if fetch_database %}
|
||||
SELECT 'd' as type, datname,
|
||||
datallowconn AND pg_catalog.has_database_privilege(datname, 'CONNECT') AS datallowconn,
|
||||
datdba, datlastsysoid
|
||||
FROM pg_database db
|
||||
UNION
|
||||
SELECT 'M', spcname, null, null, null
|
||||
FROM pg_tablespace where spcowner={{rid}}::int
|
||||
ORDER BY 1, 2
|
||||
{% endif %}
|
||||
|
||||
{% if fetch_dependents %}
|
||||
SELECT cl.relkind, COALESCE(cin.nspname, cln.nspname) as nspname,
|
||||
COALESCE(ci.relname, cl.relname) as relname, cl.relname as indname
|
||||
FROM pg_class cl
|
||||
JOIN pg_namespace cln ON cl.relnamespace=cln.oid
|
||||
LEFT OUTER JOIN pg_index ind ON ind.indexrelid=cl.oid
|
||||
LEFT OUTER JOIN pg_class ci ON ind.indrelid=ci.oid
|
||||
LEFT OUTER JOIN pg_namespace cin ON ci.relnamespace=cin.oid
|
||||
WHERE cl.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND cl.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT 'n', null, nspname, null
|
||||
FROM pg_namespace nsp
|
||||
WHERE nsp.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND nsp.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT CASE WHEN typtype='d' THEN 'd' ELSE 'y' END, null, typname, null
|
||||
FROM pg_type ty
|
||||
WHERE ty.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND ty.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT 'C', null, conname, null
|
||||
FROM pg_conversion co
|
||||
WHERE co.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND co.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT CASE WHEN prorettype=2279 THEN 'T' ELSE 'p' END, null, proname, null
|
||||
FROM pg_proc pr
|
||||
WHERE pr.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND pr.oid > {{lastsysoid}}::int
|
||||
UNION ALL SELECT 'o', null, oprname || '('::text || COALESCE(tl.typname, ''::text) || CASE WHEN tl.oid IS NOT NULL
|
||||
AND tr.oid IS NOT NULL THEN ','::text END || COALESCE(tr.typname, ''::text) || ')'::text, null
|
||||
FROM pg_operator op
|
||||
LEFT JOIN pg_type tl ON tl.oid=op.oprleft
|
||||
LEFT JOIN pg_type tr ON tr.oid=op.oprright
|
||||
WHERE op.oid IN (SELECT objid FROM pg_shdepend WHERE refobjid={{rid}}::oid) AND op.oid > {{lastsysoid}}::int
|
||||
ORDER BY 1,2,3
|
||||
{% endif %}
|
|
@ -569,5 +569,149 @@ class TablespaceView(PGChildNodeView):
|
|||
|
||||
return ajax_response(response=result)
|
||||
|
||||
@check_precondition
|
||||
def dependencies(self, gid, sid, tsid):
|
||||
"""
|
||||
This function gets the dependencies and returns an ajax response
|
||||
for the tablespace.
|
||||
|
||||
Args:
|
||||
gid: Server Group ID
|
||||
sid: Server ID
|
||||
tsid: Tablespace ID
|
||||
"""
|
||||
dependencies_result = self.get_dependencies(self.conn, tsid)
|
||||
return ajax_response(
|
||||
response=dependencies_result,
|
||||
status=200
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def dependents(self, gid, sid, tsid):
|
||||
"""
|
||||
This function gets the dependents and returns an ajax response
|
||||
for the tablespace.
|
||||
|
||||
Args:
|
||||
gid: Server Group ID
|
||||
sid: Server ID
|
||||
tsid: Tablespace ID
|
||||
"""
|
||||
dependents_result = self.get_dependents(self.conn, sid, tsid)
|
||||
return ajax_response(
|
||||
response=dependents_result,
|
||||
status=200
|
||||
)
|
||||
|
||||
def get_dependents(self, conn, sid, tsid):
|
||||
"""
|
||||
This function is used to fetch the dependents for the selected node.
|
||||
|
||||
Args:
|
||||
conn: Connection object
|
||||
sid: Server Id
|
||||
tsid: Tablespace ID
|
||||
|
||||
Returns: Dictionary of dependents for the selected node.
|
||||
"""
|
||||
# Dictionary for the object types
|
||||
types = {
|
||||
# None specified special handling for this type
|
||||
'r': 'table',
|
||||
'i': None,
|
||||
'S': 'sequence',
|
||||
'v': 'view',
|
||||
'x': 'external_table',
|
||||
'p': 'function',
|
||||
'n': 'schema',
|
||||
'y': 'type',
|
||||
'd': 'domain',
|
||||
'T': 'trigger_function',
|
||||
'C': 'conversion',
|
||||
'o': None
|
||||
}
|
||||
|
||||
# Fetching databases with CONNECT privileges status.
|
||||
query = render_template("/".join([self.template_path, 'dependents.sql']), fetch_database=True)
|
||||
status, db_result = self.conn.execute_dict(query)
|
||||
if not status:
|
||||
current_app.logger.error(db_result)
|
||||
|
||||
dependents = list()
|
||||
|
||||
# Get the server manager
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
|
||||
|
||||
for db_row in db_result['rows']:
|
||||
oid = db_row['dattablespace']
|
||||
|
||||
# Append all the databases to the dependents list if oid is same
|
||||
if tsid == oid:
|
||||
dependents.append({
|
||||
'type': 'database', 'name': '', 'field': db_row['datname']
|
||||
})
|
||||
|
||||
# If connection to the database is not allowed then continue
|
||||
# with the next database
|
||||
if not db_row['datallowconn']:
|
||||
continue
|
||||
|
||||
# Get the connection from the manager for the specified database.
|
||||
# Check the connect status and if it is not connected then create
|
||||
# a new connection to run the query and fetch the dependents.
|
||||
is_connected = True
|
||||
try:
|
||||
temp_conn = manager.connection(db_row['datname'])
|
||||
is_connected = temp_conn.connected()
|
||||
if not is_connected:
|
||||
temp_conn.connect()
|
||||
except Exception as e:
|
||||
current_app.logger.exception(e)
|
||||
|
||||
if temp_conn.connected():
|
||||
query = render_template("/".join([self.template_path, 'dependents.sql']),
|
||||
fetch_dependents=True, tsid=tsid)
|
||||
status, result = temp_conn.execute_dict(query)
|
||||
if not status:
|
||||
current_app.logger.error(result)
|
||||
|
||||
for row in result['rows']:
|
||||
rel_name = row['nspname']
|
||||
if rel_name is not None:
|
||||
rel_name += '.'
|
||||
|
||||
if rel_name is None:
|
||||
rel_name = row['relname']
|
||||
else:
|
||||
rel_name += row['relname']
|
||||
|
||||
type_name = ''
|
||||
type_str = row['relkind']
|
||||
# Fetch the type name from the dictionary
|
||||
# if type is not present in the types dictionary then
|
||||
# we will continue and not going to add it.
|
||||
if type_str[0] in types:
|
||||
|
||||
# if type is present in the types dictionary, but it's
|
||||
# value is None then it requires special handling.
|
||||
if types[type_str[0]] is None:
|
||||
if type_str[0] == 'i':
|
||||
type_name = 'index'
|
||||
rel_name = row['indname'] + ' ON ' + rel_name
|
||||
elif type_str[0] == 'o':
|
||||
type_name = 'operator'
|
||||
rel_name = row['relname']
|
||||
else:
|
||||
type_name = types[type_str[0]]
|
||||
else:
|
||||
continue
|
||||
|
||||
dependents.append({'type': type_name, 'name': rel_name, 'field': db_row['datname']})
|
||||
|
||||
# Release only those connections which we have created above.
|
||||
if not is_connected:
|
||||
manager.release(db_row['datname'])
|
||||
|
||||
return dependents
|
||||
|
||||
TablespaceView.register_node_view(blueprint)
|
||||
|
|
|
@ -48,6 +48,7 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
|
|||
label: '{{ _('Tablespace') }}',
|
||||
hasSQL: true,
|
||||
canDrop: true,
|
||||
hasDepends: true,
|
||||
Init: function() {
|
||||
/* Avoid mulitple registration of menus */
|
||||
if (this.initialized)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
{% if fetch_database %}
|
||||
SELECT datname,
|
||||
datallowconn AND pg_catalog.has_database_privilege(datname, 'CONNECT') AS datallowconn,
|
||||
dattablespace
|
||||
FROM pg_database db
|
||||
ORDER BY datname
|
||||
{% endif %}
|
||||
|
||||
{% if fetch_dependents %}
|
||||
SELECT cl.relkind, COALESCE(cin.nspname, cln.nspname) as nspname,
|
||||
COALESCE(ci.relname, cl.relname) as relname, cl.relname as indname
|
||||
FROM pg_class cl
|
||||
JOIN pg_namespace cln ON cl.relnamespace=cln.oid
|
||||
LEFT OUTER JOIN pg_index ind ON ind.indexrelid=cl.oid
|
||||
LEFT OUTER JOIN pg_class ci ON ind.indrelid=ci.oid
|
||||
LEFT OUTER JOIN pg_namespace cin ON ci.relnamespace=cin.oid,
|
||||
pg_database WHERE datname = current_database() AND
|
||||
(cl.reltablespace = {{tsid}}::oid OR (cl.reltablespace=0 AND dattablespace = {{tsid}}::oid))
|
||||
ORDER BY 1,2,3
|
||||
{% endif %}
|
|
@ -0,0 +1,20 @@
|
|||
{% if fetch_database %}
|
||||
SELECT datname,
|
||||
datallowconn AND pg_catalog.has_database_privilege(datname, 'CONNECT') AS datallowconn,
|
||||
dattablespace
|
||||
FROM pg_database db
|
||||
ORDER BY datname
|
||||
{% endif %}
|
||||
|
||||
{% if fetch_dependents %}
|
||||
SELECT cl.relkind, COALESCE(cin.nspname, cln.nspname) as nspname,
|
||||
COALESCE(ci.relname, cl.relname) as relname, cl.relname as indname
|
||||
FROM pg_class cl
|
||||
JOIN pg_namespace cln ON cl.relnamespace=cln.oid
|
||||
LEFT OUTER JOIN pg_index ind ON ind.indexrelid=cl.oid
|
||||
LEFT OUTER JOIN pg_class ci ON ind.indrelid=ci.oid
|
||||
LEFT OUTER JOIN pg_namespace cin ON ci.relnamespace=cin.oid,
|
||||
pg_database WHERE datname = current_database() AND
|
||||
(cl.reltablespace = {{tsid}}::oid OR (cl.reltablespace=0 AND dattablespace = {{tsid}}::oid))
|
||||
ORDER BY 1,2,3
|
||||
{% endif %}
|
|
@ -0,0 +1,20 @@
|
|||
{% if fetch_database %}
|
||||
SELECT datname,
|
||||
datallowconn AND pg_catalog.has_database_privilege(datname, 'CONNECT') AS datallowconn,
|
||||
dattablespace
|
||||
FROM pg_database db
|
||||
ORDER BY datname
|
||||
{% endif %}
|
||||
|
||||
{% if fetch_dependents %}
|
||||
SELECT cl.relkind, COALESCE(cin.nspname, cln.nspname) as nspname,
|
||||
COALESCE(ci.relname, cl.relname) as relname, cl.relname as indname
|
||||
FROM pg_class cl
|
||||
JOIN pg_namespace cln ON cl.relnamespace=cln.oid
|
||||
LEFT OUTER JOIN pg_index ind ON ind.indexrelid=cl.oid
|
||||
LEFT OUTER JOIN pg_class ci ON ind.indrelid=ci.oid
|
||||
LEFT OUTER JOIN pg_namespace cin ON ci.relnamespace=cin.oid,
|
||||
pg_database WHERE datname = current_database() AND
|
||||
(cl.reltablespace = {{tsid}}::oid OR (cl.reltablespace=0 AND dattablespace = {{tsid}}::oid))
|
||||
ORDER BY 1,2,3
|
||||
{% endif %}
|
|
@ -0,0 +1,90 @@
|
|||
{% if fetch_dependencies %}
|
||||
SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, ad.adsrc,
|
||||
CASE WHEN cl.relkind IS NOT NULL THEN cl.relkind || COALESCE(dep.refobjsubid::text, '')
|
||||
WHEN tg.oid IS NOT NULL THEN 'T'::text
|
||||
WHEN ty.oid IS NOT NULL THEN 'y'::text
|
||||
WHEN ns.oid IS NOT NULL THEN 'n'::text
|
||||
WHEN pr.oid IS NOT NULL THEN 'p'::text
|
||||
WHEN la.oid IS NOT NULL THEN 'l'::text
|
||||
WHEN rw.oid IS NOT NULL THEN 'R'::text
|
||||
WHEN co.oid IS NOT NULL THEN 'C'::text || contype
|
||||
WHEN ad.oid IS NOT NULL THEN 'A'::text ELSE ''
|
||||
END AS type,
|
||||
COALESCE(coc.relname, clrw.relname) AS ownertable,
|
||||
CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || '.' || att.attname
|
||||
ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname)
|
||||
END AS refname,
|
||||
COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname) AS nspname
|
||||
FROM pg_depend dep
|
||||
LEFT JOIN pg_class cl ON dep.refobjid=cl.oid
|
||||
LEFT JOIN pg_attribute att ON dep.refobjid=att.attrelid AND dep.refobjsubid=att.attnum
|
||||
LEFT JOIN pg_namespace nsc ON cl.relnamespace=nsc.oid
|
||||
LEFT JOIN pg_proc pr ON dep.refobjid=pr.oid
|
||||
LEFT JOIN pg_namespace nsp ON pr.pronamespace=nsp.oid
|
||||
LEFT JOIN pg_trigger tg ON dep.refobjid=tg.oid
|
||||
LEFT JOIN pg_type ty ON dep.refobjid=ty.oid
|
||||
LEFT JOIN pg_namespace nst ON ty.typnamespace=nst.oid
|
||||
LEFT JOIN pg_constraint co ON dep.refobjid=co.oid
|
||||
LEFT JOIN pg_class coc ON co.conrelid=coc.oid
|
||||
LEFT JOIN pg_namespace nso ON co.connamespace=nso.oid
|
||||
LEFT JOIN pg_rewrite rw ON dep.refobjid=rw.oid
|
||||
LEFT JOIN pg_class clrw ON clrw.oid=rw.ev_class
|
||||
LEFT JOIN pg_namespace nsrw ON clrw.relnamespace=nsrw.oid
|
||||
LEFT JOIN pg_language la ON dep.refobjid=la.oid
|
||||
LEFT JOIN pg_namespace ns ON dep.refobjid=ns.oid
|
||||
LEFT JOIN pg_attrdef ad ON ad.adrelid=att.attrelid AND ad.adnum=att.attnum
|
||||
{{where_clause}} AND
|
||||
refclassid IN ( SELECT oid FROM pg_class WHERE relname IN
|
||||
('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
|
||||
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger'))
|
||||
ORDER BY refclassid, cl.relkind
|
||||
{% endif %}
|
||||
|
||||
{% if fetch_role_dependencies %}
|
||||
SELECT rolname AS refname, refclassid, deptype
|
||||
FROM pg_shdepend dep
|
||||
LEFT JOIN pg_roles r ON refclassid=1260 AND refobjid=r.oid
|
||||
{{where_clause}} ORDER BY 1
|
||||
{% endif %}
|
||||
|
||||
{% if fetch_dependents %}
|
||||
SELECT DISTINCT dep.deptype, dep.classid, cl.relkind, ad.adbin, ad.adsrc,
|
||||
CASE WHEN cl.relkind IS NOT NULL THEN cl.relkind || COALESCE(dep.objsubid::text, '')
|
||||
WHEN tg.oid IS NOT NULL THEN 'T'::text
|
||||
WHEN ty.oid IS NOT NULL THEN 'y'::text
|
||||
WHEN ns.oid IS NOT NULL THEN 'n'::text
|
||||
WHEN pr.oid IS NOT NULL THEN 'p'::text
|
||||
WHEN la.oid IS NOT NULL THEN 'l'::text
|
||||
WHEN rw.oid IS NOT NULL THEN 'R'::text
|
||||
WHEN co.oid IS NOT NULL THEN 'C'::text || contype
|
||||
WHEN ad.oid IS NOT NULL THEN 'A'::text ELSE ''
|
||||
END AS type,
|
||||
COALESCE(coc.relname, clrw.relname) AS ownertable,
|
||||
CASE WHEN cl.relname IS NOT NULL AND att.attname IS NOT NULL THEN cl.relname || '.' || att.attname
|
||||
ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname)
|
||||
END AS refname,
|
||||
COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname) AS nspname
|
||||
FROM pg_depend dep
|
||||
LEFT JOIN pg_class cl ON dep.objid=cl.oid
|
||||
LEFT JOIN pg_attribute att ON dep.objid=att.attrelid AND dep.objsubid=att.attnum
|
||||
LEFT JOIN pg_namespace nsc ON cl.relnamespace=nsc.oid
|
||||
LEFT JOIN pg_proc pr ON dep.objid=pr.oid
|
||||
LEFT JOIN pg_namespace nsp ON pr.pronamespace=nsp.oid
|
||||
LEFT JOIN pg_trigger tg ON dep.objid=tg.oid
|
||||
LEFT JOIN pg_type ty ON dep.objid=ty.oid
|
||||
LEFT JOIN pg_namespace nst ON ty.typnamespace=nst.oid
|
||||
LEFT JOIN pg_constraint co ON dep.objid=co.oid
|
||||
LEFT JOIN pg_class coc ON co.conrelid=coc.oid
|
||||
LEFT JOIN pg_namespace nso ON co.connamespace=nso.oid
|
||||
LEFT JOIN pg_rewrite rw ON dep.objid=rw.oid
|
||||
LEFT JOIN pg_class clrw ON clrw.oid=rw.ev_class
|
||||
LEFT JOIN pg_namespace nsrw ON clrw.relnamespace=nsrw.oid
|
||||
LEFT JOIN pg_language la ON dep.objid=la.oid
|
||||
LEFT JOIN pg_namespace ns ON dep.objid=ns.oid
|
||||
LEFT JOIN pg_attrdef ad ON ad.oid=dep.objid
|
||||
{{where_clause}} AND
|
||||
classid IN ( SELECT oid FROM pg_class WHERE relname IN
|
||||
('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
|
||||
'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger'))
|
||||
ORDER BY classid, cl.relkind
|
||||
{% endif %}
|
|
@ -94,7 +94,7 @@ function(require, $, _, S, Bootstrap, pgAdmin, alertify, CodeMirror) {
|
|||
width: 500,
|
||||
isCloseable: false,
|
||||
isPrivate: true,
|
||||
content: '<p>Depedencies pane</p>',
|
||||
content: '<div><div class="pg-panel-depends-message">No object selected!</div><div class="pg-panel-depends-container hidden"></div></div>',
|
||||
events: panelEvents
|
||||
}),
|
||||
// Dependents of the object
|
||||
|
@ -104,7 +104,7 @@ function(require, $, _, S, Bootstrap, pgAdmin, alertify, CodeMirror) {
|
|||
width: 500,
|
||||
isCloseable: false,
|
||||
isPrivate: true,
|
||||
content: '<p>Dependent pane</p>',
|
||||
content: '<div><div class="pg-panel-depends-message">No object selected!</div><div class="pg-panel-depends-container hidden"></div></div>',
|
||||
events: panelEvents
|
||||
})/* Add hooked-in panels by extensions */{% for panel_item in current_app.panels %}{% if not panel_item.isIframe %},'{{ panel_item.name }}' : new pgAdmin.Browser.Panel({
|
||||
name: '{{ panel_item.name }}',
|
||||
|
|
|
@ -13,6 +13,7 @@ from abc import ABCMeta, abstractmethod
|
|||
import flask
|
||||
from flask.views import View, MethodViewType, with_metaclass
|
||||
from flask.ext.babel import gettext
|
||||
from flask import render_template, current_app
|
||||
import six
|
||||
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
|
@ -336,3 +337,206 @@ class PGChildNodeView(NodeView):
|
|||
nodes.extend(module.get_nodes(**kwargs))
|
||||
|
||||
return make_json_response(data=nodes)
|
||||
|
||||
def get_dependencies(self, conn, object_id, show_system_object=False, where=None):
|
||||
"""
|
||||
This function is used to fetch the dependencies for the selected node.
|
||||
|
||||
Args:
|
||||
conn: Connection object
|
||||
object_id: Object Id of the selected node.
|
||||
show_system_object: True or False (optional)
|
||||
where: where clause for the sql query (optional)
|
||||
|
||||
Returns: Dictionary of dependencies for the selected node.
|
||||
"""
|
||||
|
||||
# Set the sql_path
|
||||
sql_path = ''
|
||||
if conn.manager.version >= 90100:
|
||||
sql_path = 'depends/sql/9.1_plus'
|
||||
|
||||
if where is None:
|
||||
where_clause = "WHERE dep.objid={0}::oid".format(object_id)
|
||||
else:
|
||||
where_clause = where
|
||||
|
||||
query = render_template("/".join([sql_path, 'dependents.sql']),
|
||||
fetch_dependencies=True, where_clause=where_clause)
|
||||
# fetch the dependency for the selected object
|
||||
dependencies = self.__fetch_dependency(conn, query, show_system_object)
|
||||
|
||||
# fetch role dependencies
|
||||
if where_clause.find('subid') < 0:
|
||||
sql = render_template("/".join([sql_path, 'dependents.sql']),
|
||||
fetch_role_dependencies=True, where_clause=where_clause)
|
||||
|
||||
status, result = conn.execute_dict(sql)
|
||||
if not status:
|
||||
current_app.logger.error(result)
|
||||
|
||||
for row in result['rows']:
|
||||
ref_name = row['refname']
|
||||
dep_str = row['deptype']
|
||||
dep_type = ''
|
||||
|
||||
if dep_str == 'a':
|
||||
dep_type = 'ACL'
|
||||
elif dep_str == 'o':
|
||||
dep_type = 'Owner'
|
||||
|
||||
if row['refclassid'] == 1260:
|
||||
dependencies.append({'type': 'role', 'name': ref_name, 'field': dep_type})
|
||||
|
||||
return dependencies
|
||||
|
||||
def get_dependents(self, conn, object_id, show_system_object=False, where=None):
|
||||
"""
|
||||
This function is used to fetch the dependents for the selected node.
|
||||
|
||||
Args:
|
||||
conn: Connection object
|
||||
object_id: Object Id of the selected node.
|
||||
show_system_object: True or False (optional)
|
||||
where: where clause for the sql query (optional)
|
||||
|
||||
Returns: Dictionary of dependents for the selected node.
|
||||
"""
|
||||
# Set the sql_path
|
||||
sql_path = ''
|
||||
if conn.manager.version >= 90100:
|
||||
sql_path = 'depends/sql/9.1_plus'
|
||||
|
||||
if where is None:
|
||||
where_clause = "WHERE dep.refobjid={0}::oid".format(object_id)
|
||||
else:
|
||||
where_clause = where
|
||||
|
||||
query = render_template("/".join([sql_path, 'dependents.sql']),
|
||||
fetch_dependents=True, where_clause=where_clause)
|
||||
# fetch the dependency for the selected object
|
||||
dependents = self.__fetch_dependency(conn, query, show_system_object)
|
||||
|
||||
return dependents
|
||||
|
||||
def __fetch_dependency(self, conn, query, show_system_object):
|
||||
"""
|
||||
This function is used to fetch the dependency for the selected node.
|
||||
|
||||
Args:
|
||||
conn: Connection object
|
||||
query: sql query to fetch dependencies/dependents
|
||||
show_system_object: true or false
|
||||
|
||||
Returns: Dictionary of dependency for the selected node.
|
||||
"""
|
||||
|
||||
# Dictionary for the object types
|
||||
types = {
|
||||
# None specified special handling for this type
|
||||
'r': None,
|
||||
'i': 'index',
|
||||
'S': 'sequence',
|
||||
'v': 'view',
|
||||
'x': 'external_table',
|
||||
'p': 'function',
|
||||
'n': 'schema',
|
||||
'y': 'type',
|
||||
'T': 'trigger',
|
||||
'l': 'language',
|
||||
'R': None,
|
||||
'C': None,
|
||||
'A': None
|
||||
}
|
||||
|
||||
# Dictionary for the restrictions
|
||||
dep_types = {
|
||||
# None specified special handling for this type
|
||||
'n': 'normal',
|
||||
'a': 'auto',
|
||||
'i': None,
|
||||
'p': None
|
||||
}
|
||||
|
||||
status, result = conn.execute_dict(query)
|
||||
if not status:
|
||||
current_app.logger.error(result)
|
||||
|
||||
dependency = list()
|
||||
|
||||
for row in result['rows']:
|
||||
_ref_name = row['refname']
|
||||
type_str = row['type']
|
||||
dep_str = row['deptype']
|
||||
nsp_name = row['nspname']
|
||||
|
||||
ref_name = ''
|
||||
if nsp_name is not None:
|
||||
ref_name = nsp_name + '.'
|
||||
|
||||
type_name = ''
|
||||
|
||||
# Fetch the type name from the dictionary
|
||||
# if type is not present in the types dictionary then
|
||||
# we will continue and not going to add it.
|
||||
if type_str[0] in types:
|
||||
|
||||
# if type is present in the types dictionary, but it's
|
||||
# value is None then it requires special handling.
|
||||
if types[type_str[0]] is None:
|
||||
if type_str[0] == 'r':
|
||||
if int(type_str[1]) > 0:
|
||||
type_name = 'column'
|
||||
else:
|
||||
type_name = 'table'
|
||||
elif type_str[0] == 'R':
|
||||
type_name = 'rule'
|
||||
ref_name = _ref_name + ' ON ' + _ref_name + row['ownertable']
|
||||
_ref_name = None
|
||||
elif type_str[0] == 'C':
|
||||
if type_str[1] == 'c':
|
||||
type_name = 'check'
|
||||
elif type_str[1] == 'f':
|
||||
type_name = 'foreign_key'
|
||||
ref_name += row['ownertable'] + '.'
|
||||
elif type_str[1] == 'p':
|
||||
type_name = 'primary_key'
|
||||
elif type_str[1] == 'u':
|
||||
type_name = 'unique'
|
||||
elif type_str[1] == 'x':
|
||||
type_name = 'exclude'
|
||||
elif type_str[0] == 'A':
|
||||
# Include only functions
|
||||
if row['adbin'].startswith('{FUNCEXPR'):
|
||||
type_name = 'function'
|
||||
ref_name = row['adsrc']
|
||||
else:
|
||||
continue
|
||||
else:
|
||||
type_name = types[type_str[0]]
|
||||
else:
|
||||
continue
|
||||
|
||||
if _ref_name is not None:
|
||||
ref_name += _ref_name
|
||||
|
||||
dep_type = ''
|
||||
if dep_str[0] in dep_types:
|
||||
|
||||
# if dep_type is present in the dep_types dictionary, but it's
|
||||
# value is None then it requires special handling.
|
||||
if dep_types[dep_str[0]] is None:
|
||||
if dep_str[0] == 'i':
|
||||
if show_system_object:
|
||||
dep_type = 'internal'
|
||||
else:
|
||||
continue
|
||||
elif dep_str[0] == 'p':
|
||||
dep_type = 'pin'
|
||||
type_name = ''
|
||||
else:
|
||||
dep_type = dep_types[dep_str[0]]
|
||||
|
||||
dependency.append({'type': type_name, 'name': ref_name, 'field': dep_type})
|
||||
|
||||
return dependency
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2016, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
"""A blueprint module providing utility functions for the application."""
|
||||
|
||||
from flask import session, url_for
|
||||
from pgadmin.utils import PgAdminModule
|
||||
|
||||
MODULE_NAME = 'depends'
|
||||
|
||||
|
||||
class DependsModule(PgAdminModule):
|
||||
|
||||
def get_own_javascripts(self):
|
||||
return [{
|
||||
'name': 'pgadmin.browser.object_depends',
|
||||
'path': url_for('depends.static', filename='js/depends'),
|
||||
'when': None
|
||||
}]
|
||||
|
||||
# Initialise the module
|
||||
blueprint = DependsModule(MODULE_NAME, __name__, url_prefix='/misc/depends')
|
|
@ -0,0 +1,271 @@
|
|||
define(
|
||||
['underscore', 'underscore.string', 'jquery', 'pgadmin.browser'],
|
||||
function(_, S, $, pgBrowser) {
|
||||
|
||||
if (pgBrowser.ShowNodeDepends)
|
||||
return pgBrowser.ShowNodeDepends;
|
||||
|
||||
pgBrowser.ShowNodeDepends = pgBrowser.ShowNodeDepends || {};
|
||||
|
||||
_.extend(pgBrowser.ShowNodeDepends, {
|
||||
init: function() {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.initialized = true;
|
||||
/* Parameter is used to set the proper label of the
|
||||
* backgrid header cell.
|
||||
*/
|
||||
var dependent = true,
|
||||
dependentGrid = null, // Refer to the backgrid object render under Dependents tab
|
||||
dependenciesGrid = null; // Refer to the backgrid object render under Dependencies tab
|
||||
|
||||
_.bindAll(this, 'showDependents', 'dependentsPanelVisibilityChanged',
|
||||
'showDependencies', 'dependenciesPanelVisibilityChanged', '__updateCollection'
|
||||
);
|
||||
|
||||
// Find the panels to render the grid.
|
||||
var dependenciesPanels = this.dependenciesPanels = pgBrowser.docker.findPanels('dependencies');
|
||||
var dependentsPanels = this.dependentsPanels = pgBrowser.docker.findPanels('dependents');
|
||||
|
||||
// We will listened to the visibility change of the Dependencies and Dependents panel
|
||||
pgBrowser.Events.on('pgadmin-browser:panel-dependencies:' + wcDocker.EVENT.VISIBILITY_CHANGED,
|
||||
this.dependenciesPanelVisibilityChanged);
|
||||
pgBrowser.Events.on('pgadmin-browser:panel-dependents:' + wcDocker.EVENT.VISIBILITY_CHANGED,
|
||||
this.dependentsPanelVisibilityChanged);
|
||||
|
||||
// If Dependencies panel exists and is focused then we need to listen the browser tree selection events.
|
||||
if ((dependenciesPanels.length == 1 && dependenciesPanels[0].isVisible()) || dependenciesPanels.length != 1) {
|
||||
pgBrowser.Events.on('pgadmin-browser:tree:selected', this.showDependencies);
|
||||
}
|
||||
|
||||
// If Dependents panel exists and is focused then we need to listen the browser tree selection events.
|
||||
if ((dependentsPanels.length == 1 && dependentsPanels[0].isVisible()) || dependentsPanels.length != 1) {
|
||||
pgBrowser.Events.on('pgadmin-browser:tree:selected', this.showDependents);
|
||||
}
|
||||
|
||||
// Defining Backbone Model for Dependencies and Dependents.
|
||||
var Model = Backbone.Model.extend({
|
||||
defaults: {
|
||||
icon: 'icon-unknown',
|
||||
type: undefined,
|
||||
name: undefined,
|
||||
/* field contains 'Database Name' for 'Tablespace and Role node',
|
||||
* for other node it contains 'Restriction'.
|
||||
*/
|
||||
field: undefined
|
||||
},
|
||||
// This function is used to fetch/set the icon for the type(Function, Role, Database, ....)
|
||||
parse: function(res) {
|
||||
var node = pgBrowser.Nodes[res.type];
|
||||
res.icon = node ? (_.isFunction(node['node_image']) ?
|
||||
(node['node_image']).apply(node, [null, null]) :
|
||||
(node['node_image'] || ('icon-' + res.type))) :
|
||||
('icon-' + res.type);
|
||||
res.type = S.capitalize(res.type, true);
|
||||
return res;
|
||||
}
|
||||
});
|
||||
|
||||
// Defining Backbone Collection for Dependents.
|
||||
this.dependentCollection = new (Backbone.Collection.extend({
|
||||
model: Model
|
||||
}))(null);
|
||||
|
||||
// Defining Backbone Collection for Dependencies.
|
||||
this.dependenciesCollection = new (Backbone.Collection.extend({
|
||||
model: Model
|
||||
}))(null);
|
||||
|
||||
var self = this;
|
||||
|
||||
/* Function is used to create and render backgrid with
|
||||
* empty collection. We just want to add backgrid into the
|
||||
* panel only once.
|
||||
*/
|
||||
var appendGridToPanel = function(collection, panel, is_dependent) {
|
||||
var $container = panel[0].layout().$table.find('.pg-panel-content'),
|
||||
$gridContainer = $container.find('.pg-panel-depends-container'),
|
||||
grid = new Backgrid.Grid({
|
||||
columns: [
|
||||
{
|
||||
name : 'type',
|
||||
label: 'Type',
|
||||
// Extend it to render the icon as per the type.
|
||||
cell: Backgrid.Cell.extend({
|
||||
render: function() {
|
||||
Backgrid.Cell.prototype.render.apply(this, arguments);
|
||||
this.$el.addClass(this.model.get('icon')).css({"padding-left": "18px"});
|
||||
return this;
|
||||
}
|
||||
}),
|
||||
editable: false
|
||||
},
|
||||
{
|
||||
name : 'name',
|
||||
label: 'Name',
|
||||
cell: 'string',
|
||||
editable: false
|
||||
},
|
||||
{
|
||||
name : 'field',
|
||||
label: '', // label kept blank, it will change dynamically
|
||||
cell: 'string',
|
||||
editable: false
|
||||
}
|
||||
],
|
||||
|
||||
collection: collection,
|
||||
className: "backgrid table-bordered"
|
||||
});
|
||||
|
||||
// Condition is used to save grid object to change the label of the header.
|
||||
if (is_dependent)
|
||||
self.dependentGrid = grid;
|
||||
else
|
||||
self.dependenciesGrid = grid;
|
||||
|
||||
$gridContainer.append(grid.render().el);
|
||||
};
|
||||
|
||||
appendGridToPanel(this.dependentCollection, this.dependentsPanels, true);
|
||||
appendGridToPanel(this.dependenciesCollection, this.dependenciesPanels, false);
|
||||
},
|
||||
|
||||
// Fetch the actual data and update the collection
|
||||
__updateCollection: function(collection, panel, url, messages, node) {
|
||||
var msg = messages[0],
|
||||
$container = panel[0].layout().$table.find('.pg-panel-content'),
|
||||
$msgContainer = $container.find('.pg-panel-depends-message'),
|
||||
$gridContainer = $container.find('.pg-panel-depends-container');
|
||||
|
||||
// Hide the grid container and show the default message container
|
||||
if (!$gridContainer.hasClass('hidden'))
|
||||
$gridContainer.addClass('hidden');
|
||||
$msgContainer.removeClass('hidden');
|
||||
|
||||
if (node) {
|
||||
msg = messages[1];
|
||||
/* We fetch the Dependencies and Dependents tab only for
|
||||
* those node who set the parameter hasDepends to true.
|
||||
*/
|
||||
if (node.hasDepends) {
|
||||
/* Set the message because ajax request may take time to
|
||||
* fetch the information from the server.
|
||||
*/
|
||||
msg = messages[2];
|
||||
$msgContainer.text(msg);
|
||||
|
||||
/* Updating the label for the 'field' type of the backbone model.
|
||||
* Label should be "Database" if the node type is tablespace or role
|
||||
* and dependent tab is selected. For other nodes and dependencies tab
|
||||
* it should be 'Restriction'.
|
||||
*/
|
||||
if (this.dependent && (node.type == 'tablespace' || node.type == 'role'))
|
||||
this.dependentGrid.columns.models[2].set({'label': 'Database'});
|
||||
else {
|
||||
this.dependenciesGrid.columns.models[2].set({'label': 'Restriction'});
|
||||
this.dependentGrid.columns.models[2].set({'label': 'Restriction'});
|
||||
}
|
||||
|
||||
// Set the url, fetch the data and update the collection
|
||||
collection.url = url;
|
||||
collection.fetch({
|
||||
reset: true,
|
||||
success: function(res) {
|
||||
|
||||
// In case of success hide the message container and show the grid container.
|
||||
$gridContainer.removeClass('hidden');
|
||||
$msgContainer.addClass('hidden');
|
||||
},
|
||||
error: function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (msg != '') {
|
||||
$msgContainer.text(msg);
|
||||
}
|
||||
},
|
||||
showDependents: function(item, data, node) {
|
||||
/**
|
||||
* We can't start fetching the Dependents immediately, it is possible the user
|
||||
* is just using the keyboard to select the node, and just traversing
|
||||
* through. We will wait for some time before fetching the Dependents
|
||||
**/
|
||||
var self = this;
|
||||
self.dependent = true;
|
||||
if (self.timeout) {
|
||||
clearTimeout(self.timeout);
|
||||
}
|
||||
self.timeout = setTimeout(
|
||||
self.__updateCollection(
|
||||
self.dependentCollection,
|
||||
self.dependentsPanels,
|
||||
node.generate_url(item, 'dependent', data, true),
|
||||
['-- No object selected!', '-- No dependent information is available for the current selection.',
|
||||
'-- Please wait while we fetch the dependent information from the server.'],
|
||||
node
|
||||
), 400
|
||||
);
|
||||
},
|
||||
dependentsPanelVisibilityChanged: function(panel) {
|
||||
if (panel.isVisible()) {
|
||||
var t = pgBrowser.tree,
|
||||
i = t.selected(),
|
||||
d = i && t.itemData(i),
|
||||
n = i && d && pgBrowser.Nodes[d._type];
|
||||
|
||||
pgBrowser.ShowNodeDepends.showDependents.apply(pgBrowser.ShowNodeDepends, [i, d, n]);
|
||||
|
||||
// We will start listening the tree selection event.
|
||||
pgBrowser.Events.on('pgadmin-browser:tree:selected', pgBrowser.ShowNodeDepends.showDependents);
|
||||
} else {
|
||||
|
||||
// We don't need to listen the tree item selection event.
|
||||
pgBrowser.Events.off('pgadmin-browser:tree:selected', pgBrowser.ShowNodeDepends.showDependents);
|
||||
}
|
||||
},
|
||||
showDependencies: function(item, data, node) {
|
||||
/**
|
||||
* We can't start fetching the Dependencies immediately, it is possible the user
|
||||
* is just using the keyboard to select the node, and just traversing
|
||||
* through. We will wait for some time before fetching the Dependencies
|
||||
**/
|
||||
var self = this;
|
||||
self.dependent = false;
|
||||
if (self.timeout) {
|
||||
clearTimeout(self.timeout);
|
||||
}
|
||||
self.timeout = setTimeout(
|
||||
self.__updateCollection(
|
||||
self.dependenciesCollection,
|
||||
self.dependenciesPanels,
|
||||
node.generate_url(item, 'dependency', data, true),
|
||||
['-- No object selected!', '-- No dependency information is available for the current selection.',
|
||||
'-- Please wait while we fetch the dependency information from the server.'],
|
||||
node
|
||||
), 400
|
||||
);
|
||||
},
|
||||
dependenciesPanelVisibilityChanged: function(panel) {
|
||||
if (panel.isVisible()) {
|
||||
var t = pgBrowser.tree,
|
||||
i = t.selected(),
|
||||
d = i && t.itemData(i),
|
||||
n = i && d && pgBrowser.Nodes[d._type];
|
||||
|
||||
pgBrowser.ShowNodeDepends.showDependencies.apply(pgBrowser.ShowNodeDepends, [i, d, n]);
|
||||
|
||||
// We will start listening the tree selection event.
|
||||
pgBrowser.Events.on('pgadmin-browser:tree:selected', pgBrowser.ShowNodeDepends.showDependencies);
|
||||
} else {
|
||||
// We don't need to listen the tree item selection event.
|
||||
pgBrowser.Events.off('pgadmin-browser:tree:selected', pgBrowser.ShowNodeDepends.showDependencies);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return pgBrowser.ShowNodeDepends;
|
||||
});
|
Loading…
Reference in New Issue