mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-22 08:46:39 -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',
|
'pgadmin', 'backbone', 'backgrid', 'codemirror', 'pgadmin.misc.explain',
|
||||||
'sources/selection/grid_selector', 'sources/selection/clipboard',
|
'sources/selection/grid_selector', 'sources/selection/clipboard',
|
||||||
'sources/selection/copy_data',
|
'sources/selection/copy_data',
|
||||||
|
'sources/selection/set_staged_rows',
|
||||||
'slickgrid', 'bootstrap', 'pgadmin.browser', 'wcdocker',
|
'slickgrid', 'bootstrap', 'pgadmin.browser', 'wcdocker',
|
||||||
'codemirror/mode/sql/sql', 'codemirror/addon/selection/mark-selection',
|
'codemirror/mode/sql/sql', 'codemirror/addon/selection/mark-selection',
|
||||||
'codemirror/addon/selection/active-line', 'codemirror/addon/fold/foldcode',
|
'codemirror/addon/selection/active-line', 'codemirror/addon/fold/foldcode',
|
||||||
@ -25,7 +26,7 @@ define([
|
|||||||
'slickgrid/slick.grid'
|
'slickgrid/slick.grid'
|
||||||
], function(
|
], function(
|
||||||
gettext, $, _, S, alertify, pgAdmin, Backbone, Backgrid, CodeMirror,
|
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 */
|
/* Return back, this has been called more than once */
|
||||||
if (pgAdmin.SqlEditor)
|
if (pgAdmin.SqlEditor)
|
||||||
@ -691,88 +692,8 @@ define([
|
|||||||
|
|
||||||
// Listener function to watch selected rows from grid
|
// Listener function to watch selected rows from grid
|
||||||
if (editor_data.selection) {
|
if (editor_data.selection) {
|
||||||
editor_data.selection.onSelectedRangesChanged.subscribe(function(e, args) {
|
editor_data.selection.onSelectedRangesChanged.subscribe(
|
||||||
var collection = this.grid.getData(),
|
setStagedRows.bind(editor_data));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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