mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-25 18:20:20 -06:00
Extract row staging into it's own module with tests.
This commit is contained in:
parent
0d05385585
commit
8d8e7dab3c
114
web/pgadmin/static/js/selection/set_staged_rows.js
Normal file
114
web/pgadmin/static/js/selection/set_staged_rows.js
Normal file
@ -0,0 +1,114 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2017, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
define(
|
||||
[
|
||||
'jquery',
|
||||
'underscore'
|
||||
],
|
||||
function ($, _) {
|
||||
function disableButton(selector) {
|
||||
$(selector).prop('disabled', true);
|
||||
}
|
||||
|
||||
function enableButton(selector) {
|
||||
$(selector).prop('disabled', false);
|
||||
}
|
||||
|
||||
function getRowPrimaryKeyValuesToStage(selectedRows, primaryKeyColumnIndices, gridData) {
|
||||
return _.reduce(selectedRows, function (primaryKeyValuesToStage, dataGridRowIndex) {
|
||||
var gridRow = gridData[dataGridRowIndex];
|
||||
|
||||
if (isRowMissingPrimaryKeys(gridRow, primaryKeyColumnIndices)) {
|
||||
return primaryKeyValuesToStage;
|
||||
}
|
||||
|
||||
var tempPK = gridRow.__temp_PK;
|
||||
primaryKeyValuesToStage[tempPK] = getSingleRowPrimaryKeyValueToStage(primaryKeyColumnIndices, gridRow);
|
||||
|
||||
return primaryKeyValuesToStage;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function isRowMissingPrimaryKeys(gridRow, primaryKeyColumnIndices) {
|
||||
if (_.isUndefined(gridRow)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !_.isUndefined(
|
||||
_.find(primaryKeyColumnIndices, function (pkIndex) {
|
||||
return _.isUndefined(gridRow[pkIndex]);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function getSingleRowPrimaryKeyValueToStage(primaryKeyColumnIndices, gridRow) {
|
||||
var rowToStage = {};
|
||||
if (primaryKeyColumnIndices.length) {
|
||||
_.each(_.keys(gridRow), function (columnPos) {
|
||||
if (_.contains(primaryKeyColumnIndices, Number(columnPos)))
|
||||
rowToStage[columnPos] = gridRow[columnPos];
|
||||
})
|
||||
}
|
||||
return rowToStage;
|
||||
}
|
||||
|
||||
function getPrimaryKeysForSelectedRows(self, selectedRows) {
|
||||
var primaryKeyColumnIndices = _.map(_.keys(self.keys), function (columnName) {
|
||||
var columnInfo = _.findWhere(self.columns, {name: columnName});
|
||||
return columnInfo['pos'];
|
||||
});
|
||||
|
||||
var gridData = self.grid.getData();
|
||||
var stagedRows = getRowPrimaryKeyValuesToStage(selectedRows, primaryKeyColumnIndices, gridData);
|
||||
|
||||
return stagedRows;
|
||||
}
|
||||
|
||||
var setStagedRows = function (e, args) {
|
||||
var self = this;
|
||||
|
||||
function setStagedRows(rowsToStage) {
|
||||
self.editor.handler.data_store.staged_rows = rowsToStage;
|
||||
}
|
||||
|
||||
function isEditMode() {
|
||||
return self.editor.handler.can_edit;
|
||||
}
|
||||
|
||||
disableButton('#btn-delete-row');
|
||||
disableButton('#btn-copy-row');
|
||||
|
||||
if (!_.has(this.selection, 'getSelectedRows')) {
|
||||
setStagedRows({});
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedRows = this.selection.getSelectedRows();
|
||||
|
||||
if (selectedRows.length > 0) {
|
||||
var stagedRows = getPrimaryKeysForSelectedRows(self, selectedRows);
|
||||
setStagedRows(stagedRows);
|
||||
if (_.isEmpty(stagedRows)) {
|
||||
this.selection.setSelectedRows([]);
|
||||
}
|
||||
|
||||
enableButton('#btn-copy-row');
|
||||
if (isEditMode()) {
|
||||
enableButton('#btn-delete-row');
|
||||
}
|
||||
} else {
|
||||
setStagedRows({});
|
||||
}
|
||||
};
|
||||
return setStagedRows;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -3,6 +3,7 @@ define([
|
||||
'pgadmin', 'backbone', 'backgrid', 'codemirror', 'pgadmin.misc.explain',
|
||||
'sources/selection/grid_selector', 'sources/selection/clipboard',
|
||||
'sources/selection/copy_data',
|
||||
'sources/selection/set_staged_rows',
|
||||
'slickgrid', 'bootstrap', 'pgadmin.browser', 'wcdocker',
|
||||
'codemirror/mode/sql/sql', 'codemirror/addon/selection/mark-selection',
|
||||
'codemirror/addon/selection/active-line', 'codemirror/addon/fold/foldcode',
|
||||
@ -25,7 +26,7 @@ define([
|
||||
'slickgrid/slick.grid'
|
||||
], function(
|
||||
gettext, $, _, S, alertify, pgAdmin, Backbone, Backgrid, CodeMirror,
|
||||
pgExplain, GridSelector, clipboard, copyData
|
||||
pgExplain, GridSelector, clipboard, copyData, setStagedRows
|
||||
) {
|
||||
/* Return back, this has been called more than once */
|
||||
if (pgAdmin.SqlEditor)
|
||||
@ -691,88 +692,8 @@ define([
|
||||
|
||||
// Listener function to watch selected rows from grid
|
||||
if (editor_data.selection) {
|
||||
editor_data.selection.onSelectedRangesChanged.subscribe(function(e, args) {
|
||||
var collection = this.grid.getData(),
|
||||
primary_key_list = _.keys(this.keys),
|
||||
_tmp_keys = [],
|
||||
_columns = this.columns,
|
||||
rows_for_stage = {},
|
||||
selected_rows_list = [];
|
||||
|
||||
// Only if entire row(s) are selected via check box
|
||||
if(_.has(this.selection, 'getSelectedRows')) {
|
||||
selected_rows_list = this.selection.getSelectedRows();
|
||||
// We will map selected row primary key name with position
|
||||
// For each Primary key
|
||||
_.each(primary_key_list, function(p) {
|
||||
// For each columns search primary key position
|
||||
_.each(_columns, function(c) {
|
||||
if(c.name == p) {
|
||||
_tmp_keys.push(c.pos);
|
||||
}
|
||||
});
|
||||
});
|
||||
// Now assign mapped temp PK to PK
|
||||
primary_key_list = _tmp_keys;
|
||||
|
||||
// Check if selected is new row ?
|
||||
// Allow to delete if yes
|
||||
var count = selected_rows_list.length-1,
|
||||
cell_el = this.grid.getCellNode(selected_rows_list[count],0),
|
||||
parent_el = $(cell_el).parent(),
|
||||
is_new_row = $(parent_el).hasClass('new_row');
|
||||
|
||||
// Clear selection model if row primary keys is set to default
|
||||
var row_data = _.clone(collection[selected_rows_list[count]]),
|
||||
is_primary_key = true;
|
||||
|
||||
// Primary key validation
|
||||
_.each(primary_key_list, function(pk) {
|
||||
if (!(_.has(row_data, pk)) || row_data[pk] == undefined) {
|
||||
is_primary_key = false;
|
||||
}
|
||||
})
|
||||
|
||||
if (primary_key_list.length && !is_primary_key && !is_new_row) {
|
||||
this.selection.setSelectedRows([]);
|
||||
selected_rows_list = [];
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the object as no rows to delete
|
||||
// and disable delete/copy rows button
|
||||
var clear_staged_rows = function() {
|
||||
rows_for_stage = {};
|
||||
$("#btn-delete-row").prop('disabled', true);
|
||||
$("#btn-copy-row").prop('disabled', true);
|
||||
}
|
||||
|
||||
// If any row(s) selected ?
|
||||
if(selected_rows_list.length) {
|
||||
if(this.editor.handler.can_edit)
|
||||
// Enable delete rows and copy rows button
|
||||
$("#btn-delete-row").prop('disabled', false);
|
||||
$("#btn-copy-row").prop('disabled', false);
|
||||
// Collect primary key data from collection as needed for stage row
|
||||
_.each(selected_rows_list, function(row_index) {
|
||||
var row_data = collection[row_index],
|
||||
p_keys_list = _.pick(row_data, primary_key_list),
|
||||
is_primary_key = Object.keys(p_keys_list).length ?
|
||||
p_keys_list[0] : undefined;
|
||||
|
||||
// Store Primary key data for selected rows
|
||||
if (!_.isUndefined(row_data) && !_.isUndefined(p_keys_list)) {
|
||||
// check for invalid row
|
||||
rows_for_stage[row_data.__temp_PK] = p_keys_list;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
//clear staged rows
|
||||
clear_staged_rows();
|
||||
}
|
||||
// Update main data store
|
||||
this.editor.handler.data_store.staged_rows = rows_for_stage;
|
||||
}.bind(editor_data));
|
||||
editor_data.selection.onSelectedRangesChanged.subscribe(
|
||||
setStagedRows.bind(editor_data));
|
||||
}
|
||||
|
||||
|
||||
|
238
web/regression/javascript/selection/set_staged_rows_spec.js
Normal file
238
web/regression/javascript/selection/set_staged_rows_spec.js
Normal file
@ -0,0 +1,238 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2017, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
define([
|
||||
"jquery",
|
||||
"underscore",
|
||||
"sources/selection/set_staged_rows",
|
||||
], function ($, _, SetStagedRows) {
|
||||
describe('when no full rows are selected', function () {
|
||||
var sqlEditorObj, deleteButton, copyButton;
|
||||
beforeEach(function () {
|
||||
var gridSpy = jasmine.createSpyObj('gridSpy', ['getData', 'getCellNode']);
|
||||
gridSpy.getData.and.returnValue([
|
||||
{0: 'one', 1: 'two', __temp_PK: '123'},
|
||||
{0: 'three', 1: 'four', __temp_PK: '456'},
|
||||
{0: 'five', 1: 'six', __temp_PK: '789'},
|
||||
{0: 'seven', 1: 'eight', __temp_PK: '432'}
|
||||
]);
|
||||
deleteButton = $('<button id="btn-delete-row"></button>');
|
||||
copyButton = $('<button id="btn-copy-row"></button>');
|
||||
sqlEditorObj = {
|
||||
grid: gridSpy,
|
||||
editor: {
|
||||
handler: {
|
||||
data_store: {
|
||||
staged_rows: {1: [1, 2]}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
$('body').append(deleteButton);
|
||||
$('body').append(copyButton);
|
||||
deleteButton.prop('disabled', false);
|
||||
copyButton.prop('disabled', false);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
copyButton.remove();
|
||||
deleteButton.remove();
|
||||
});
|
||||
|
||||
describe('when getSelectedRows is not present in the selection model', function () {
|
||||
beforeEach(function () {
|
||||
SetStagedRows.call(sqlEditorObj, {}, {});
|
||||
});
|
||||
it('should disable the delete row button', function () {
|
||||
expect($('#btn-delete-row').prop('disabled')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should disable the copy row button', function () {
|
||||
expect($('#btn-copy-row').prop('disabled')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should clear staged rows', function () {
|
||||
expect(sqlEditorObj.editor.handler.data_store.staged_rows).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when getSelectedRows is present in the selection model', function () {
|
||||
beforeEach(function () {
|
||||
var selectionSpy = jasmine.createSpyObj('selectionSpy', ['getSelectedRows', 'setSelectedRows']);
|
||||
selectionSpy.getSelectedRows.and.returnValue([]);
|
||||
sqlEditorObj.selection = selectionSpy;
|
||||
SetStagedRows.call(sqlEditorObj, {}, {});
|
||||
});
|
||||
|
||||
it('should disable the delete row button', function () {
|
||||
expect($('#btn-delete-row').prop('disabled')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should disable the copy row button', function () {
|
||||
expect($('#btn-copy-row').prop('disabled')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should clear staged rows', function () {
|
||||
expect(sqlEditorObj.editor.handler.data_store.staged_rows).toEqual({});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when 2 full rows are selected', function () {
|
||||
describe('when getSelectedRows is present in the selection model', function () {
|
||||
var sqlEditorObj, gridSpy, deleteButton, copyButton;
|
||||
beforeEach(function () {
|
||||
gridSpy = jasmine.createSpyObj('gridSpy', ['getData', 'getCellNode']);
|
||||
gridSpy.getData.and.returnValue([
|
||||
{0: 'one', 1: 'two', __temp_PK: '123'},
|
||||
{0: 'three', 1: 'four', __temp_PK: '456'},
|
||||
{0: 'five', 1: 'six', __temp_PK: '789'},
|
||||
{0: 'seven', 1: 'eight', __temp_PK: '432'}
|
||||
]);
|
||||
|
||||
var selectionSpy = jasmine.createSpyObj('selectionSpy', ['getSelectedRows', 'setSelectedRows']);
|
||||
selectionSpy.getSelectedRows.and.returnValue([1, 2]);
|
||||
|
||||
deleteButton = $('<button id="btn-delete-row"></button>');
|
||||
copyButton = $('<button id="btn-copy-row"></button>');
|
||||
|
||||
sqlEditorObj = {
|
||||
grid: gridSpy,
|
||||
editor: {
|
||||
handler: {
|
||||
data_store: {
|
||||
staged_rows: {'456': {}}
|
||||
},
|
||||
can_edit: false
|
||||
}
|
||||
},
|
||||
keys: null,
|
||||
selection: selectionSpy,
|
||||
columns: [
|
||||
{
|
||||
name: 'a pk column',
|
||||
pos: 0
|
||||
},
|
||||
{
|
||||
name: 'some column',
|
||||
pos: 1
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
$('body').append(deleteButton);
|
||||
$('body').append(copyButton);
|
||||
|
||||
deleteButton.prop('disabled', true);
|
||||
copyButton.prop('disabled', true);
|
||||
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
copyButton.remove();
|
||||
deleteButton.remove();
|
||||
});
|
||||
|
||||
describe('when table does not have primary keys', function () {
|
||||
it('should enable the copy row button', function () {
|
||||
SetStagedRows.call(sqlEditorObj, {}, {});
|
||||
expect($('#btn-copy-row').prop('disabled')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not enable the delete row button', function () {
|
||||
SetStagedRows.call(sqlEditorObj, {}, {});
|
||||
expect($('#btn-delete-row').prop('disabled')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update staged rows with the __temp_PK value of the new Selected Rows', function () {
|
||||
SetStagedRows.call(sqlEditorObj, {}, {});
|
||||
expect(sqlEditorObj.editor.handler.data_store.staged_rows).toEqual({'456': {}, '789': {}});
|
||||
});
|
||||
|
||||
describe('the user can edit', function () {
|
||||
it('should enable the delete row button', function () {
|
||||
sqlEditorObj.editor.handler.can_edit = true;
|
||||
SetStagedRows.call(sqlEditorObj, {}, {});
|
||||
expect($('#btn-delete-row').prop('disabled')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when table has primary keys', function () {
|
||||
beforeEach(function () {
|
||||
sqlEditorObj.keys = {'a pk column': 'varchar'};
|
||||
sqlEditorObj.editor.handler.data_store.staged_rows = {'456': {0: 'three'}};
|
||||
});
|
||||
|
||||
describe('selected rows have primary key', function () {
|
||||
it('should set the staged rows correctly', function () {
|
||||
SetStagedRows.call(sqlEditorObj, {}, {});
|
||||
expect(sqlEditorObj.editor.handler.data_store.staged_rows).toEqual(
|
||||
{'456': {0: 'three'}, '789': {0: 'five'}});
|
||||
});
|
||||
|
||||
it('should not clear selected rows in Cell Selection Model', function () {
|
||||
SetStagedRows.call(sqlEditorObj, {}, {});
|
||||
expect(sqlEditorObj.selection.setSelectedRows).not.toHaveBeenCalledWith();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('selected rows missing primary key', function () {
|
||||
beforeEach(function () {
|
||||
gridSpy.getData.and.returnValue([
|
||||
{0: 'one', 1: 'two', __temp_PK: '123'},
|
||||
{1: 'four', __temp_PK: '456'},
|
||||
{1: 'six', __temp_PK: '789'},
|
||||
{0: 'seven', 1: 'eight', __temp_PK: '432'}
|
||||
]);
|
||||
});
|
||||
|
||||
it('should clear the staged rows', function () {
|
||||
SetStagedRows.call(sqlEditorObj, {}, {});
|
||||
expect(sqlEditorObj.editor.handler.data_store.staged_rows).toEqual({});
|
||||
});
|
||||
|
||||
it('should clear selected rows in Cell Selection Model', function () {
|
||||
SetStagedRows.call(sqlEditorObj, {}, {});
|
||||
expect(sqlEditorObj.selection.setSelectedRows).toHaveBeenCalledWith([]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('when the selected row is a new row', function () {
|
||||
var parentDiv;
|
||||
beforeEach(function () {
|
||||
var childDiv = $('<div></div>');
|
||||
parentDiv = $('<div class="new_row"></div>');
|
||||
parentDiv.append(childDiv);
|
||||
$('body').append(parentDiv);
|
||||
gridSpy.getCellNode.and.returnValue(childDiv);
|
||||
SetStagedRows.call(sqlEditorObj, {}, {});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
parentDiv.remove();
|
||||
});
|
||||
|
||||
it('should not clear the staged rows', function () {
|
||||
expect(sqlEditorObj.editor.handler.data_store.staged_rows).toEqual({
|
||||
'456': {0: 'three'},
|
||||
'789': {0: 'five'}
|
||||
});
|
||||
});
|
||||
|
||||
it('should not clear selected rows in Cell Selection Model', function () {
|
||||
expect(sqlEditorObj.selection.setSelectedRows).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user