mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-03 04:00:55 -06:00
Resolve schema diff dependencies by selecting the appropriate node automatically and maintain the order in the generated script. Fixes #5730
This commit is contained in:
parent
7dd313f5fc
commit
5b688cf949
@ -43,4 +43,5 @@ Bug fixes
|
||||
| `Issue #5710 <https://redmine.postgresql.org/issues/5710>`_ - Fixed an issue when comparing the table with a trigger throwing error in schema diff.
|
||||
| `Issue #5713 <https://redmine.postgresql.org/issues/5713>`_ - Corrected DROP SQL syntax for catalog.
|
||||
| `Issue #5716 <https://redmine.postgresql.org/issues/5716>`_ - Fixed an issue where ajax call continues to fire even after disconnect the database server.
|
||||
| `Issue #5724 <https://redmine.postgresql.org/issues/5724>`_ - Clarify some of the differences when running in server mode in the docs.
|
||||
| `Issue #5724 <https://redmine.postgresql.org/issues/5724>`_ - Clarify some of the differences when running in server mode in the docs.
|
||||
| `Issue #5730 <https://redmine.postgresql.org/issues/5730>`_ - Resolve schema diff dependencies by selecting the appropriate node automatically and maintain the order in the generated script.
|
@ -344,6 +344,17 @@ def get_server(sid, did):
|
||||
)
|
||||
@login_required
|
||||
def connect_server(sid):
|
||||
# Check if server is already connected then no need to reconnect again.
|
||||
driver = get_driver(PG_DEFAULT_DRIVER)
|
||||
manager = driver.connection_manager(sid)
|
||||
conn = manager.connection()
|
||||
if conn.connected():
|
||||
return make_json_response(
|
||||
success=1,
|
||||
info=gettext("Server connected."),
|
||||
data={}
|
||||
)
|
||||
|
||||
server = Server.query.filter_by(id=sid).first()
|
||||
view = SchemaDiffRegistry.get_node_view('server')
|
||||
return view.connect(server.servergroup_id, sid)
|
||||
|
@ -514,6 +514,7 @@ let SchemaDiffFooterView = Backform.Form.extend({
|
||||
return this;
|
||||
},
|
||||
});
|
||||
|
||||
export {
|
||||
SchemaDiffSelect2Control,
|
||||
SchemaDiffHeaderView,
|
||||
|
@ -0,0 +1,237 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
function handleDependencies() {
|
||||
event.stopPropagation();
|
||||
let isChecked = event.target.checked || (event.target.checked === undefined &&
|
||||
event.target.className && event.target.className.indexOf('unchecked') == -1);
|
||||
|
||||
let isHeaderSelected = event.target.id.includes('header-selector');
|
||||
|
||||
if (this.gridContext && this.gridContext.rowIndex && _.isUndefined(this.gridContext.row.rows)) {
|
||||
// Single Row Selection
|
||||
let rowData = this.grid.getData().getItem(this.gridContext.rowIndex);
|
||||
this.gridContext = {};
|
||||
if (rowData.status) {
|
||||
let depRows = this.selectDependencies(rowData, isChecked);
|
||||
this.selectedRowCount = this.grid.getSelectedRows().length;
|
||||
if (isChecked && depRows.length > 0)
|
||||
this.grid.setSelectedRows(depRows);
|
||||
else if (!isChecked)
|
||||
this.grid.setSelectedRows(this.grid.getSelectedRows().filter(x => !depRows.includes(x)));
|
||||
|
||||
this.ddlCompare(rowData);
|
||||
}
|
||||
} else if((this.gridContext && this.gridContext.row && !_.isUndefined(this.gridContext.row.rows)) ||
|
||||
this.selectedRowCount != this.grid.getSelectedRows().length) {
|
||||
|
||||
// Group / All Rows Selection
|
||||
this.selectedRowCount = this.grid.getSelectedRows().length;
|
||||
|
||||
if (this.gridContext.row && this.gridContext.row.__group) {
|
||||
let context = this.gridContext;
|
||||
this.gridContext = {};
|
||||
this.selectDependenciesForGroup(isChecked, context);
|
||||
} else {
|
||||
this.gridContext = {};
|
||||
this.selectDependenciesForAll(isChecked, isHeaderSelected);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.grid.getSelectedRows().length > 0) {
|
||||
this.header.$el.find('button#generate-script').removeAttr('disabled');
|
||||
} else {
|
||||
this.header.$el.find('button#generate-script').attr('disabled', true);
|
||||
}
|
||||
}
|
||||
|
||||
function selectDependenciesForGroup(isChecked, context) {
|
||||
let self = this,
|
||||
finalRows = [];
|
||||
|
||||
if (!isChecked) {
|
||||
_.each(context.row.rows, function(row) {
|
||||
if (row && row.status && row.status.toLowerCase() != 'identical' ) {
|
||||
let d = self.selectDependencies(row, isChecked);
|
||||
finalRows = finalRows.concat(d);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
_.each(self.grid.getSelectedRows(), function(row) {
|
||||
let data = self.grid.getData().getItem(row);
|
||||
if (data.status && data.status.toLowerCase() != 'identical') {
|
||||
finalRows = finalRows.concat(self.selectDependencies(data, isChecked));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
finalRows = [...new Set(finalRows)];
|
||||
|
||||
if (isChecked)
|
||||
self.grid.setSelectedRows(finalRows);
|
||||
else {
|
||||
let filterRows = [];
|
||||
filterRows = self.grid.getSelectedRows().filter(x => !finalRows.includes(x));
|
||||
|
||||
self.selectedRowCount = filterRows.length;
|
||||
self.grid.setSelectedRows(filterRows);
|
||||
}
|
||||
}
|
||||
|
||||
function selectDependenciesForAll(isChecked, isHeaderSelected) {
|
||||
let self = this,
|
||||
finalRows = [];
|
||||
|
||||
if(!isChecked && isHeaderSelected) {
|
||||
self.dataView.getItems().map(function(el) {
|
||||
el.dependentCount = [];
|
||||
el.dependLevel = 1;
|
||||
});
|
||||
self.selectedRowCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
_.each(self.grid.getSelectedRows(), function(row) {
|
||||
let data = self.grid.getData().getItem(row);
|
||||
if (data.status) {
|
||||
finalRows = finalRows.concat(self.selectDependencies(data, isChecked));
|
||||
}
|
||||
});
|
||||
|
||||
finalRows = [...new Set(finalRows)];
|
||||
|
||||
if (isChecked && finalRows.length > 0)
|
||||
self.grid.setSelectedRows(finalRows);
|
||||
else if (!isChecked) {
|
||||
let filterRows = [];
|
||||
filterRows = self.grid.getSelectedRows().filter(x => !finalRows.includes(x));
|
||||
|
||||
self.selectedRowCount = filterRows.length;
|
||||
self.grid.setSelectedRows(filterRows);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function selectDependencies(data, isChecked) {
|
||||
let self = this,
|
||||
rows = [],
|
||||
setDependencies = undefined,
|
||||
setOrigDependencies = undefined,
|
||||
finalRows = [];
|
||||
|
||||
if (!data.dependLevel || !isChecked) data.dependLevel = 1;
|
||||
if (!data.dependentCount || !isChecked) data.dependentCount = [];
|
||||
|
||||
if (data.status && data.status.toLowerCase() == 'identical') {
|
||||
self.selectedRowCount = self.grid.getSelectedRows().length;
|
||||
return [];
|
||||
}
|
||||
|
||||
setDependencies = function(rowData, dependencies, isChecked) {
|
||||
_.each(dependencies, function(dependency) {
|
||||
if (dependency.length == 0) return;
|
||||
let dependencyData = [];
|
||||
|
||||
dependencyData = self.dataView.getItems().filter(item => item.type == dependency.type && item.oid == dependency.oid);
|
||||
|
||||
if (dependencyData.length > 0) {
|
||||
dependencyData = dependencyData[0];
|
||||
if (!dependencyData.dependentCount) dependencyData.dependentCount = [];
|
||||
|
||||
let groupData = [];
|
||||
|
||||
if (dependencyData.status && dependencyData.status.toLowerCase() != 'identical') {
|
||||
groupData = self.dataView.getGroups().find(
|
||||
(item) => { if (dependencyData.group_name == item.groupingKey) return item.groups; }
|
||||
);
|
||||
|
||||
if (groupData && groupData.groups) {
|
||||
groupData = groupData.groups.find(
|
||||
(item) => { return item.groupingKey == dependencyData.group_name + ':|:' + dependencyData.type; }
|
||||
);
|
||||
|
||||
if (groupData && groupData.collapsed == 1)
|
||||
self.dataView.expandGroup(dependencyData.group_name + ':|:' + dependencyData.type);
|
||||
}
|
||||
|
||||
if (isChecked || _.isUndefined(isChecked)) {
|
||||
dependencyData.dependLevel = rowData.dependLevel + 1;
|
||||
if (dependencyData.dependentCount.indexOf(rowData.oid) === -1)
|
||||
dependencyData.dependentCount.push(rowData.oid);
|
||||
rows[rows.length] = dependencyData;
|
||||
} else {
|
||||
dependencyData.dependentCount.splice(dependencyData.dependentCount.indexOf(rowData.oid), 1);
|
||||
if (dependencyData.dependentCount.length == 0) {
|
||||
rows[rows.length] = dependencyData;
|
||||
dependencyData.dependLevel = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.keys(dependencyData.dependencies).length > 0) {
|
||||
if (dependencyData.dependentCount.indexOf(rowData.oid) !== -1 ) {
|
||||
let depCirRows = dependencyData.dependencies.filter(x => x.oid !== rowData.oid);
|
||||
if (!dependencyData.orig_dependencies)
|
||||
dependencyData.orig_dependencies = Object.assign([], dependencyData.dependencies);
|
||||
dependencyData.dependencies = depCirRows;
|
||||
}
|
||||
setDependencies(dependencyData, dependencyData.dependencies, isChecked);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
setDependencies(data, data.dependencies, isChecked);
|
||||
|
||||
setOrigDependencies = function(dependencies) {
|
||||
_.each(dependencies, function(dependency) {
|
||||
if (dependency.length == 0) return;
|
||||
let dependencyData = [];
|
||||
|
||||
dependencyData = self.dataView.getItems().filter(item => item.type == dependency.type && item.oid == dependency.oid);
|
||||
|
||||
if (dependencyData.length > 0) {
|
||||
dependencyData = dependencyData[0];
|
||||
|
||||
if (dependencyData.orig_dependencies && Object.keys(dependencyData.orig_dependencies).length > 0) {
|
||||
if (!dependencyData.dependentCount) dependencyData.dependentCount = [];
|
||||
|
||||
if (dependencyData.status && dependencyData.status.toLowerCase() != 'identical') {
|
||||
dependencyData.dependencies = dependencyData.orig_dependencies;
|
||||
dependencyData.orig_dependencies = [];
|
||||
}
|
||||
if (dependencyData.dependencies.length > 0) {
|
||||
setOrigDependencies(dependencyData.dependencies);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
setOrigDependencies(data.dependencies);
|
||||
|
||||
if (isChecked) finalRows = self.grid.getSelectedRows();
|
||||
|
||||
_.each(rows, function(row) {
|
||||
let r = self.grid.getData().getRowByItem(row);
|
||||
if(!_.isUndefined(r) && finalRows.indexOf(r) === -1 ) {
|
||||
finalRows.push(self.grid.getData().getRowByItem(row));
|
||||
}
|
||||
});
|
||||
|
||||
self.selectedRowCount = finalRows.length;
|
||||
return finalRows;
|
||||
}
|
||||
|
||||
export {
|
||||
handleDependencies,
|
||||
selectDependenciesForGroup,
|
||||
selectDependenciesForAll,
|
||||
selectDependencies,
|
||||
};
|
@ -19,9 +19,12 @@ import {generateScript} from 'tools/datagrid/static/js/show_query_tool';
|
||||
import 'pgadmin.sqleditor';
|
||||
import pgWindow from 'sources/window';
|
||||
|
||||
import {SchemaDiffSelect2Control, SchemaDiffHeaderView,
|
||||
import { SchemaDiffSelect2Control, SchemaDiffHeaderView,
|
||||
SchemaDiffFooterView, SchemaDiffSqlControl} from './schema_diff.backform';
|
||||
|
||||
import { handleDependencies, selectDependenciesForGroup,
|
||||
selectDependenciesForAll, selectDependencies } from './schema_diff_dependency';
|
||||
|
||||
var wcDocker = window.wcDocker;
|
||||
|
||||
export default class SchemaDiffUI {
|
||||
@ -198,10 +201,11 @@ export default class SchemaDiffUI {
|
||||
script_header;
|
||||
|
||||
script_header = gettext('-- This script was generated by a beta version of the Schema Diff utility in pgAdmin 4. \n');
|
||||
script_header += gettext('-- This version does not include dependency resolution, and may require manual changes \n');
|
||||
script_header += gettext('-- to the script to ensure changes are applied in the correct order.\n');
|
||||
script_header += gettext('-- For the circular dependencies, the order in which Schema Diff writes the objects is not very sophisticated \n');
|
||||
script_header += gettext('-- and may require manual changes to the script to ensure changes are applied in the correct order.\n');
|
||||
script_header += gettext('-- Please report an issue for any failure with the reproduction steps. \n');
|
||||
|
||||
|
||||
_.each(url_params, function(key, val) {
|
||||
url_params[key] = parseInt(val, 10);
|
||||
});
|
||||
@ -249,14 +253,22 @@ export default class SchemaDiffUI {
|
||||
};
|
||||
|
||||
if (sel_rows.length > 0) {
|
||||
let script_body = '';
|
||||
let script_array = {1: [], 2: [], 3: [], 4: [], 5: []},
|
||||
script_body = '';
|
||||
for (var row = 0; row < sel_rows.length; row++) {
|
||||
let data = self.grid.getData().getItem(sel_rows[row]);
|
||||
if(!_.isUndefined(data.diff_ddl)) {
|
||||
script_body += data.diff_ddl + '\n\n';
|
||||
if (!(data.dependLevel in script_array)) script_array[data.dependLevel] = [];
|
||||
script_array[data.dependLevel].push(data.diff_ddl);
|
||||
}
|
||||
}
|
||||
|
||||
_.each(Object.keys(script_array).reverse(), function(s) {
|
||||
if (script_array[s].length > 0) {
|
||||
script_body += script_array[s].join('\n') + '\n\n';
|
||||
}
|
||||
});
|
||||
|
||||
generated_script = script_header + 'BEGIN;' + '\n' + script_body + 'END;';
|
||||
open_query_tool();
|
||||
} else if (!_.isUndefined(self.model.get('diff_ddl'))) {
|
||||
@ -362,9 +374,10 @@ export default class SchemaDiffUI {
|
||||
|
||||
// Change Row css on the basis of item status
|
||||
self.dataView.getItemMetadata = function(row) {
|
||||
var item = self.dataView.getItem(row);
|
||||
let item = self.dataView.getItem(row),
|
||||
group_item = groupItemMetadataProvider.getGroupRowMetadata(item);
|
||||
if (item.__group) {
|
||||
return groupItemMetadataProvider.getGroupRowMetadata(item);
|
||||
return group_item;
|
||||
}
|
||||
|
||||
if(item.status === 'Different') {
|
||||
@ -393,6 +406,17 @@ export default class SchemaDiffUI {
|
||||
|
||||
self.dataView.syncGridSelection(grid, true, true);
|
||||
|
||||
grid.onMouseEnter.subscribe(function (evt) {
|
||||
var cell = grid.getCellFromEvent(evt);
|
||||
self.gridContext = {};
|
||||
self.gridContext.rowIndex = cell.row;
|
||||
self.gridContext.row = grid.getDataItem(cell.row);
|
||||
}.bind(self));
|
||||
|
||||
grid.onMouseLeave.subscribe(function () {
|
||||
self.gridContext = {};
|
||||
});
|
||||
|
||||
grid.onClick.subscribe(function(e, args) {
|
||||
if (args.row) {
|
||||
data = args.grid.getData().getItem(args.row);
|
||||
@ -400,9 +424,9 @@ export default class SchemaDiffUI {
|
||||
}
|
||||
}.bind(self));
|
||||
|
||||
grid.onSelectedRowsChanged.subscribe(self.handle_generate_button.bind(self));
|
||||
grid.onSelectedRowsChanged.subscribe(self.handleDependencies.bind(this));
|
||||
|
||||
self.model.on('change:diff_ddl', self.handle_generate_button.bind(self));
|
||||
self.model.on('change:diff_ddl', self.handleDependencies.bind(self));
|
||||
|
||||
$('#schema-diff-grid').on('keyup', function() {
|
||||
if ((event.keyCode == 38 || event.keyCode ==40) && this.grid.getActiveCell().row) {
|
||||
@ -414,11 +438,10 @@ export default class SchemaDiffUI {
|
||||
self.render_grid_data(data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
render_grid_data(data) {
|
||||
var self = this;
|
||||
self.grid.setSelectedRows([]);
|
||||
self.selected_row_count = self.grid.getSelectedRows().length;
|
||||
data.sort((a, b) => (a.label > b.label) ? 1 : (a.label === b.label) ? ((a.title > b.title) ? 1 : -1) : -1);
|
||||
self.dataView.beginUpdate();
|
||||
self.dataView.setItems(data);
|
||||
@ -503,7 +526,7 @@ export default class SchemaDiffUI {
|
||||
'source_ddl': undefined,
|
||||
'target_ddl': undefined,
|
||||
'diff_ddl': undefined,
|
||||
});
|
||||
}, {silent: true});
|
||||
|
||||
if(data.status && data.status.toLowerCase() == 'identical') {
|
||||
var url_params = self.selection;
|
||||
@ -541,7 +564,7 @@ export default class SchemaDiffUI {
|
||||
'source_ddl': data.source_ddl,
|
||||
'target_ddl': data.target_ddl,
|
||||
'diff_ddl': data.diff_ddl,
|
||||
});
|
||||
}, {silent: true});
|
||||
|
||||
self.footer.render();
|
||||
}
|
||||
@ -855,3 +878,8 @@ export default class SchemaDiffUI {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
SchemaDiffUI.prototype.handleDependencies = handleDependencies;
|
||||
SchemaDiffUI.prototype.selectDependenciesForGroup = selectDependenciesForGroup;
|
||||
SchemaDiffUI.prototype.selectDependenciesForAll = selectDependenciesForAll;
|
||||
SchemaDiffUI.prototype.selectDependencies = selectDependencies;
|
||||
|
Loading…
Reference in New Issue
Block a user