mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Add support for generating ERD for a schema. #4580
This commit is contained in:
@@ -18,7 +18,14 @@ The Entity-Relationship Diagram (ERD) tool is a database design tool that provid
|
|||||||
:alt: ERD tool window
|
:alt: ERD tool window
|
||||||
:align: center
|
:align: center
|
||||||
|
|
||||||
You can open multiple copies of the ERD tool in individual tabs simultaneously. To close a copy of the ERD tool, click the *X* in the upper-right hand corner of the tab bar.
|
You can open multiple copies of the ERD tool in individual tabs simultaneously.
|
||||||
|
You can also generate an ERD from a database, schema or a table.
|
||||||
|
|
||||||
|
* The ERD for database will fetch all the tables from all the schemas of the database and plot them with foreign key links.
|
||||||
|
* The ERD for schema will fetch all the tables from a schema and plot them with foreign key links. If any table refers to a table in another
|
||||||
|
schema, then that link/foreign key will be removed.
|
||||||
|
* The ERD for table will fetch all the tables linked directly or indirectly to mentioned table. You can change the depth of traversal from :ref:`Preferences <preferences>`.
|
||||||
|
|
||||||
|
|
||||||
Toolbar
|
Toolbar
|
||||||
*******
|
*******
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import { getNodeListByName } from '../../../../../../static/js/node_ajax';
|
|||||||
|
|
||||||
define('pgadmin.node.schema', [
|
define('pgadmin.node.schema', [
|
||||||
'sources/gettext', 'sources/url_for',
|
'sources/gettext', 'sources/url_for',
|
||||||
'pgadmin.browser', 'pgadmin.browser.collection',
|
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.browser.collection',
|
||||||
], function(gettext, url_for, pgBrowser) {
|
], function(gettext, url_for, pgAdmin, pgBrowser) {
|
||||||
|
|
||||||
// Extend the browser's collection class for schema collection
|
// Extend the browser's collection class for schema collection
|
||||||
if (!pgBrowser.Nodes['coll-schema']) {
|
if (!pgBrowser.Nodes['coll-schema']) {
|
||||||
@@ -61,12 +61,25 @@ define('pgadmin.node.schema', [
|
|||||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
category: 'create', priority: 1, label: gettext('Schema...'),
|
category: 'create', priority: 1, label: gettext('Schema...'),
|
||||||
data: {action: 'create'}, enable: 'can_create_schema',
|
data: {action: 'create'}, enable: 'can_create_schema',
|
||||||
},
|
},{
|
||||||
]);
|
name: 'generate_erd', node: 'schema', module: this,
|
||||||
|
applies: ['object', 'context'], callback: 'generate_erd',
|
||||||
|
category: 'erd', priority: 5, label: gettext('ERD For Schema')
|
||||||
|
}]);
|
||||||
},
|
},
|
||||||
can_create_schema: function(node) {
|
can_create_schema: function(node) {
|
||||||
return pgBrowser.Nodes['database'].is_conn_allow.call(this, node);
|
return pgBrowser.Nodes['database'].is_conn_allow.call(this, node);
|
||||||
},
|
},
|
||||||
|
callbacks: {
|
||||||
|
/* Generate the ERD */
|
||||||
|
generate_erd: function(args) {
|
||||||
|
let input = args || {},
|
||||||
|
t = pgBrowser.tree,
|
||||||
|
i = input.item || t.selected(),
|
||||||
|
d = i ? t.itemData(i) : undefined;
|
||||||
|
pgAdmin.Tools.ERD.showErdTool(d, i, true);
|
||||||
|
},
|
||||||
|
},
|
||||||
getSchema: function(treeNodeInfo, itemNodeData) {
|
getSchema: function(treeNodeInfo, itemNodeData) {
|
||||||
let schemaObj = pgBrowser.Nodes['schema'];
|
let schemaObj = pgBrowser.Nodes['schema'];
|
||||||
return new PGSchema(
|
return new PGSchema(
|
||||||
|
|||||||
@@ -131,9 +131,11 @@ export default class ERDModule {
|
|||||||
+`&did=${parentData.database._id}`
|
+`&did=${parentData.database._id}`
|
||||||
+`&gen=${gen}`;
|
+`&gen=${gen}`;
|
||||||
|
|
||||||
|
if(parentData.schema) {
|
||||||
|
openUrl += `&scid=${parentData.schema._id}`;
|
||||||
|
}
|
||||||
if(parentData.table) {
|
if(parentData.table) {
|
||||||
openUrl += `&scid=${parentData.schema._id}`
|
openUrl += `&tid=${parentData.table._id}`;
|
||||||
+`&tid=${parentData.table._id}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return openUrl;
|
return openUrl;
|
||||||
|
|||||||
@@ -615,7 +615,7 @@ export default class ERDCore {
|
|||||||
_.forIn(tableNodesDict, (node, uid)=>{
|
_.forIn(tableNodesDict, (node, uid)=>{
|
||||||
let nodeData = node.getData();
|
let nodeData = node.getData();
|
||||||
if(nodeData.foreign_key) {
|
if(nodeData.foreign_key) {
|
||||||
nodeData.foreign_key.forEach((theFk)=>{
|
nodeData.foreign_key = nodeData.foreign_key.filter((theFk)=>{
|
||||||
delete theFk.oid;
|
delete theFk.oid;
|
||||||
theFk = theFk.columns[0];
|
theFk = theFk.columns[0];
|
||||||
theFk.references = oidUidMap[theFk.references];
|
theFk.references = oidUidMap[theFk.references];
|
||||||
@@ -627,11 +627,17 @@ export default class ERDCore {
|
|||||||
};
|
};
|
||||||
let sourceNode = tableNodesDict[newData.referenced_table_uid];
|
let sourceNode = tableNodesDict[newData.referenced_table_uid];
|
||||||
let targetNode = tableNodesDict[newData.local_table_uid];
|
let targetNode = tableNodesDict[newData.local_table_uid];
|
||||||
|
// When generating for schema, there may be a reference to another schema table
|
||||||
|
// We'll remove the FK completely in such cases.
|
||||||
|
if(!sourceNode || !targetNode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
newData.local_column_attnum = _.find(targetNode.getColumns(), (col)=>col.name==theFk.local_column).attnum;
|
newData.local_column_attnum = _.find(targetNode.getColumns(), (col)=>col.name==theFk.local_column).attnum;
|
||||||
newData.referenced_column_attnum = _.find(sourceNode.getColumns(), (col)=>col.name==theFk.referenced).attnum;
|
newData.referenced_column_attnum = _.find(sourceNode.getColumns(), (col)=>col.name==theFk.referenced).attnum;
|
||||||
|
|
||||||
this.addLink(newData, 'onetomany');
|
this.addLink(newData, 'onetomany');
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -32,12 +32,16 @@ class ERDTableView(BaseTableView, DataTypeReader):
|
|||||||
return DataTypeReader.get_types(self, self.conn, condition, True)
|
return DataTypeReader.get_types(self, self.conn, condition, True)
|
||||||
|
|
||||||
@BaseTableView.check_precondition
|
@BaseTableView.check_precondition
|
||||||
def fetch_all_tables(self, did=None, sid=None):
|
def fetch_all_tables(self, did=None, sid=None, scid=None):
|
||||||
status, schemas = get_schemas(self.conn, show_system_objects=False)
|
|
||||||
if not status:
|
|
||||||
return status, schemas
|
|
||||||
|
|
||||||
all_tables = []
|
all_tables = []
|
||||||
|
schemas = {'rows': []}
|
||||||
|
if scid is None:
|
||||||
|
status, schemas = get_schemas(self.conn, show_system_objects=False)
|
||||||
|
if not status:
|
||||||
|
return status, schemas
|
||||||
|
else:
|
||||||
|
schemas['rows'].append({'oid': scid})
|
||||||
|
|
||||||
for row in schemas['rows']:
|
for row in schemas['rows']:
|
||||||
status, res = \
|
status, res = \
|
||||||
BaseTableView.fetch_tables(self, sid, did, row['oid'],
|
BaseTableView.fetch_tables(self, sid, did, row['oid'],
|
||||||
@@ -111,6 +115,9 @@ class ERDHelper:
|
|||||||
if tid is None and scid is None:
|
if tid is None and scid is None:
|
||||||
status, res = self.table_view.fetch_all_tables(
|
status, res = self.table_view.fetch_all_tables(
|
||||||
did=self.did, sid=self.sid)
|
did=self.did, sid=self.sid)
|
||||||
|
elif tid is None:
|
||||||
|
status, res = self.table_view.fetch_all_tables(
|
||||||
|
did=self.did, sid=self.sid, scid=scid)
|
||||||
else:
|
else:
|
||||||
prefs = Preferences.module('erd')
|
prefs = Preferences.module('erd')
|
||||||
table_relation_depth = prefs.preference('table_relation_depth')
|
table_relation_depth = prefs.preference('table_relation_depth')
|
||||||
|
|||||||
Reference in New Issue
Block a user