Hello Hackers!
Re. https://www.postgresql.org/message-id/CAFS4TJb-
7VTQQrnOi0g6MaoxMfEK9LzCds2yG%2BByS-mLHwydQA%40mail.gmail.com
We extracted the function bound to onSelectedRangesChanged from sqleditor!
- we read through the existing implementation and wrapped it in
`web/regression/javascript/selection/set_staged_rows_spec.js`
- we made some changes for clarity
Thanks,
Joao and George
diff --git a/web/pgadmin/static/js/selection/set_staged_rows.js
b/web/pgadmin/static/js/selection/set_staged_rows.js
new file mode 100644
index 00000000..cace7282
--- /dev/null
+++ b/web/pgadmin/static/js/selection/set_staged_rows.js
@@ -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;
+ }
+);
+
+
diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
index 597c4367..c83d1b36 100644
--- a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
+++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
@@ -4,6 +4,7 @@ define(
'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',
@@ -27,7 +28,7 @@ define(
'slickgrid/slick.grid'
],
function(
- $, _, S, alertify, pgAdmin, Backbone, Backgrid, CodeMirror, pgExplain,
GridSelector, clipboard, copyData
+ $, _, S, alertify, pgAdmin, Backbone, Backgrid, CodeMirror, pgExplain,
GridSelector, clipboard, copyData, setStagedRows
) {
/* Return back, this has been called more than once */
if (pgAdmin.SqlEditor)
@@ -693,84 +694,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 = _.has(row_data, primary_key_list) &&
- row_data[0] != undefined ? true : 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));
}
diff --git a/web/regression/javascript/selection/set_staged_rows_spec.js
b/web/regression/javascript/selection/set_staged_rows_spec.js
new file mode 100644
index 00000000..11e293fd
--- /dev/null
+++ b/web/regression/javascript/selection/set_staged_rows_spec.js
@@ -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();
+ });
+ });
+ });
+ });
+ });
+});
\ No newline at end of file
--
Sent via pgadmin-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers