mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
1) Added support for unique keys in ERD. Fixes #7249
2) Fixed an issue where foreign key relationships do not update when the primary key is modified. Fixes #7197
This commit is contained in:
committed by
Akshay Joshi
parent
9f992a9e5d
commit
903b300b9e
@@ -268,10 +268,55 @@ export default class ERDCore {
|
||||
}
|
||||
|
||||
syncTableLinks(tableNode, oldTableData) {
|
||||
let self = this;
|
||||
let tableData = tableNode.getData();
|
||||
let tableNodesDict = this.getModel().getNodesDict();
|
||||
const tableNodesDict = this.getModel().getNodesDict();
|
||||
|
||||
/* Remove the links if column dropped or primary key removed */
|
||||
_.differenceWith(oldTableData.columns, tableData.columns, function(existing, incoming) {
|
||||
if(existing.attnum == incoming.attnum && existing.is_primary_key && !incoming.is_primary_key) {
|
||||
return false;
|
||||
}
|
||||
return existing.attnum == incoming.attnum;
|
||||
}).forEach((col)=>{
|
||||
let existPort = tableNode.getPort(tableNode.getPortName(col.attnum));
|
||||
if(existPort) {
|
||||
Object.values(existPort.getLinks()).forEach((link)=>{
|
||||
self.removeOneToManyLink(link);
|
||||
});
|
||||
}
|
||||
tableNode.removePort(existPort);
|
||||
});
|
||||
|
||||
/* Sync the name changes in references FK */
|
||||
Object.values(tableNode.getPorts()).forEach((port)=>{
|
||||
if(port.getSubtype() != 'one') {
|
||||
return;
|
||||
}
|
||||
Object.values(port.getLinks()).forEach((link)=>{
|
||||
let linkData = link.getData();
|
||||
let fkTableNode = this.getModel().getNodesDict()[linkData.local_table_uid];
|
||||
|
||||
let newForeingKeys = [];
|
||||
fkTableNode.getData().foreign_key?.forEach((theFkRow)=>{
|
||||
for(let fkColumn of theFkRow.columns) {
|
||||
let attnum = _.find(oldTableData.columns, (c)=>c.name==fkColumn.referenced).attnum;
|
||||
fkColumn.referenced = _.find(tableData.columns, (colm)=>colm.attnum==attnum).name;
|
||||
fkColumn.references_table_name = tableData.name;
|
||||
}
|
||||
newForeingKeys.push(theFkRow);
|
||||
});
|
||||
fkTableNode.setData({
|
||||
...fkTableNode.getData(),
|
||||
foreign_key: newForeingKeys,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/* Sync the changed/removed/added foreign keys */
|
||||
tableData = tableNode.getData();
|
||||
const addLink = (theFk)=>{
|
||||
if(!theFk) return;
|
||||
let newData = {
|
||||
local_table_uid: tableNode.getID(),
|
||||
local_column_attnum: undefined,
|
||||
@@ -287,6 +332,7 @@ export default class ERDCore {
|
||||
};
|
||||
|
||||
const removeLink = (theFk)=>{
|
||||
if(!theFk) return;
|
||||
let attnum = _.find(tableNode.getColumns(), (col)=>col.name==theFk.local_column).attnum;
|
||||
let existPort = tableNode.getPort(tableNode.getPortName(attnum));
|
||||
if(existPort && existPort.getSubtype() == 'many') {
|
||||
@@ -316,9 +362,12 @@ export default class ERDCore {
|
||||
tableData.foreign_key[rowIndx].columns,
|
||||
'cid'
|
||||
);
|
||||
if(changeDiffCols.removed.length > 0 || changeDiffCols.added.length > 0) {
|
||||
removeLink(changeDiffCols.removed[0]);
|
||||
addLink(changeDiffCols.added[0]);
|
||||
if(changeDiffCols.removed.length > 0) {
|
||||
/* any change in columns length remove all and create new link */
|
||||
oldTableData.foreign_key[rowIndx].columns.forEach((col)=>{
|
||||
removeLink(col);
|
||||
});
|
||||
addLink(tableData.foreign_key[rowIndx].columns[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import TableIcon from 'top/browser/server_groups/servers/databases/schemas/table
|
||||
import PrimaryKeyIcon from 'top/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/static/img/primary_key.svg';
|
||||
import ForeignKeyIcon from 'top/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/img/foreign_key.svg';
|
||||
import ColumnIcon from 'top/browser/server_groups/servers/databases/schemas/tables/columns/static/img/column.svg';
|
||||
import UniqueKeyIcon from 'top/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/static/img/unique_constraint.svg';
|
||||
import PropTypes from 'prop-types';
|
||||
import gettext from 'sources/gettext';
|
||||
|
||||
@@ -94,17 +95,6 @@ export class TableNodeModel extends DefaultNodeModel {
|
||||
}
|
||||
|
||||
setData(data) {
|
||||
let self = this;
|
||||
/* Remove the links if column dropped or primary key removed */
|
||||
_.differenceWith(this._data.columns, data.columns, function(existing, incoming) {
|
||||
return existing.attnum == incoming.attnum && incoming.is_primary_key == true;
|
||||
}).forEach((col)=>{
|
||||
let existPort = self.getPort(self.getPortName(col.attnum));
|
||||
if(existPort && existPort.getSubtype() == 'one') {
|
||||
existPort.removeAllLinks();
|
||||
self.removePort(existPort);
|
||||
}
|
||||
});
|
||||
this._data = data;
|
||||
this.fireEvent({}, 'nodeUpdated');
|
||||
}
|
||||
@@ -172,18 +162,23 @@ export class TableNodeWidget extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
generateColumn(col, tableData) {
|
||||
generateColumn(col, localFkCols, localUkCols) {
|
||||
let port = this.props.node.getPort(this.props.node.getPortName(col.attnum));
|
||||
let icon = ColumnIcon;
|
||||
let localFkCols = [];
|
||||
(tableData.foreign_key||[]).forEach((fk)=>{
|
||||
localFkCols.push(...fk.columns.map((c)=>c.local_column));
|
||||
});
|
||||
/* Less priority */
|
||||
if(localUkCols.indexOf(col.name) > -1) {
|
||||
icon = UniqueKeyIcon;
|
||||
}
|
||||
if(col.is_primary_key) {
|
||||
icon = PrimaryKeyIcon;
|
||||
} else if(localFkCols.indexOf(col.name) > -1) {
|
||||
icon = ForeignKeyIcon;
|
||||
}
|
||||
|
||||
let cltype = col.cltype;
|
||||
if(col.attlen) {
|
||||
cltype += '('+ col.attlen + (col.attprecision ? ',' + col.attprecision : '') +')';
|
||||
}
|
||||
return (
|
||||
<div className='d-flex col-row' key={col.attnum}>
|
||||
<div className='d-flex col-row-data'>
|
||||
@@ -191,7 +186,7 @@ export class TableNodeWidget extends React.Component {
|
||||
<div className="my-auto">
|
||||
<span className='col-name'>{col.name}</span>
|
||||
{this.state.show_details &&
|
||||
<span className='col-datatype'>{col.cltype}{col.attlen ? ('('+ col.attlen + (col.attprecision ? ','+col.attprecision : '') +')') : ''}</span>}
|
||||
<span className='col-datatype'>{cltype}</span>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-auto col-row-port">{this.generatePort(port)}</div>
|
||||
@@ -216,6 +211,14 @@ export class TableNodeWidget extends React.Component {
|
||||
render() {
|
||||
let tableData = this.props.node.getData();
|
||||
let tableMetaData = this.props.node.getMetadata();
|
||||
let localFkCols = [];
|
||||
(tableData.foreign_key||[]).forEach((fk)=>{
|
||||
localFkCols.push(...fk.columns.map((c)=>c.local_column));
|
||||
});
|
||||
let localUkCols = [];
|
||||
(tableData.unique_constraint||[]).forEach((uk)=>{
|
||||
localUkCols.push(...uk.columns.map((c)=>c.column));
|
||||
});
|
||||
return (
|
||||
<div className={'table-node ' + (this.props.node.isSelected() ? 'selected': '') } onDoubleClick={()=>{this.props.node.fireEvent({}, 'editTable');}}>
|
||||
<div className="table-toolbar">
|
||||
@@ -243,7 +246,7 @@ export class TableNodeWidget extends React.Component {
|
||||
<div className="table-name my-auto">{tableData.name}</div>
|
||||
</div>
|
||||
<div className="table-cols">
|
||||
{_.map(tableData.columns, (col)=>this.generateColumn(col, tableData))}
|
||||
{_.map(tableData.columns, (col)=>this.generateColumn(col, localFkCols, localUkCols))}
|
||||
</div>
|
||||
</>}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user