diff --git a/web/package.json b/web/package.json index 3ce86a11c..f8d876073 100644 --- a/web/package.json +++ b/web/package.json @@ -84,6 +84,7 @@ "slickgrid": "git+https://github.com/6pac/SlickGrid.git#2.3.7", "snapsvg": "^0.5.1", "spectrum-colorpicker": "^1.8.0", + "sprintf-js": "^1.1.1", "underscore": "^1.8.3", "underscore.string": "^3.3.4", "watchify": "~3.9.0", diff --git a/web/pgadmin/static/js/sqleditor/calculate_query_run_time.js b/web/pgadmin/static/js/sqleditor/calculate_query_run_time.js new file mode 100644 index 000000000..b9b6b0c75 --- /dev/null +++ b/web/pgadmin/static/js/sqleditor/calculate_query_run_time.js @@ -0,0 +1,33 @@ +///////////////////////////////////////////////////////////// +// +// pgAdmin 4 - PostgreSQL Tools +// +// Copyright (C) 2013 - 2018, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +////////////////////////////////////////////////////////////// + +import moment from 'moment'; + +export function calculateQueryRunTime(startTime, endTime) { + const tempEndDate = moment(endTime); + let miliseconds = tempEndDate.diff(startTime); + let seconds = tempEndDate.diff(startTime, 'seconds'); + const minutes = tempEndDate.diff(startTime, 'minutes'); + + let result = ''; + if (minutes > 0) { + result += minutes + ' min '; + seconds -= minutes * 60; + } + + if (seconds > 0) { + result += seconds + ' secs '; + miliseconds -= seconds * 1000; + } + + if(minutes <= 0) { + result += miliseconds + ' msec'; + } + return result.trim(); +} diff --git a/web/pgadmin/static/js/sqleditor/call_render_after_poll.js b/web/pgadmin/static/js/sqleditor/call_render_after_poll.js new file mode 100644 index 000000000..6d1e3836f --- /dev/null +++ b/web/pgadmin/static/js/sqleditor/call_render_after_poll.js @@ -0,0 +1,52 @@ +///////////////////////////////////////////////////////////// +// +// pgAdmin 4 - PostgreSQL Tools +// +// Copyright (C) 2013 - 2018, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +////////////////////////////////////////////////////////////// + +import {calculateQueryRunTime} from './calculate_query_run_time'; +import gettext from '../gettext'; +import {sprintf} from 'sprintf-js'; + +function hasResultsToDisplay(res) { + return res.colinfo != null; +} + +function isQueryTool(sqlEditor) { + return sqlEditor.is_query_tool; +} + +function isNotificationEnabled(sqlEditor) { + return sqlEditor.info_notifier_timeout >= 0; +} + +export function callRenderAfterPoll(sqlEditor, alertify, res) { + sqlEditor.query_end_time = new Date(); + sqlEditor.rows_affected = res.rows_affected; + sqlEditor.has_more_rows = res.has_more_rows; + + if (hasResultsToDisplay(res)) { + sqlEditor._render(res); + } else { + sqlEditor.total_time = calculateQueryRunTime( + sqlEditor.query_start_time, + sqlEditor.query_end_time); + const msg = sprintf( + gettext('Query returned successfully in %s.'), sqlEditor.total_time); + res.result += '\n\n' + msg; + sqlEditor.update_msg_history(true, res.result, false); + if (isNotificationEnabled(sqlEditor)) { + alertify.success(msg, sqlEditor.info_notifier_timeout); + } + } + + if (isQueryTool(sqlEditor)) { + sqlEditor.disable_tool_buttons(false); + } + + sqlEditor.setIsQueryRunning(false); + sqlEditor.trigger('pgadmin-sqleditor:loading-icon:hide'); +} diff --git a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js index 923ccead5..56bdaf1bb 100644 --- a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js +++ b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js @@ -20,6 +20,8 @@ define('tools.querytool', [ 'sources/keyboard_shortcuts', 'sources/sqleditor/query_tool_actions', 'pgadmin.datagrid', + 'sources/sqleditor/calculate_query_run_time', + 'sources/sqleditor/call_render_after_poll', 'sources/../bundle/slickgrid', 'pgadmin.file_manager', 'backgrid.sizeable.columns', @@ -32,7 +34,8 @@ define('tools.querytool', [ pgExplain, GridSelector, ActiveCellCapture, clipboard, copyData, RangeSelectionHelper, handleQueryOutputKeyboardEvent, XCellSelectionModel, setStagedRows, SqlEditorUtils, ExecuteQuery, transaction, HistoryBundle, queryHistory, React, ReactDOM, - keyboardShortcuts, queryToolActions, Datagrid) { + keyboardShortcuts, queryToolActions, Datagrid, + calculateQueryRunTime, callRenderAfterPoll) { /* Return back, this has been called more than once */ if (pgAdmin.SqlEditor) return pgAdmin.SqlEditor; @@ -2224,37 +2227,8 @@ define('tools.querytool', [ // This is a wrapper to call_render function // We need this because we have separated columns route & result route // We need to combine both result here in wrapper before rendering grid - call_render_after_poll: function(res) { - var self = this; - self.query_end_time = new Date(); - self.rows_affected = res.rows_affected; - self.has_more_rows = res.has_more_rows; - - /* If no column information is available it means query - runs successfully with no result to display. In this - case no need to call render function. - */ - if (res.colinfo != null) - self._render(res); - else { - // Show message in message and history tab in case of query tool - self.total_time = self.get_query_run_time(self.query_start_time, self.query_end_time); - var msg = S(gettext('Query returned successfully in %s.')).sprintf(self.total_time).value(); - res.result += '\n\n' + msg; - self.update_msg_history(true, res.result, false); - // Display the notifier if the timeout is set to >= 0 - if (self.info_notifier_timeout >= 0) { - alertify.success(msg, self.info_notifier_timeout); - } - } - - // Enable/Disable query tool button only if is_query_tool is true. - if (self.is_query_tool) { - self.disable_tool_buttons(false); - $('#btn-cancel-query').prop('disabled', true); - } - is_query_running = false; - self.trigger('pgadmin-sqleditor:loading-icon:hide'); + call_render_after_poll: function(queryResult) { + callRenderAfterPoll.callRenderAfterPoll(this,alertify,queryResult); }, @@ -2329,7 +2303,10 @@ define('tools.querytool', [ ); // Show message in message and history tab in case of query tool - self.total_time = self.get_query_run_time(self.query_start_time, self.query_end_time); + self.total_time = calculateQueryRunTime.calculateQueryRunTime( + self.query_start_time, + self.query_end_time + ); var msg1 = S(gettext('Successfully run. Total query runtime: %s.')).sprintf(self.total_time).value(); var msg2 = S(gettext('%s rows affected.')).sprintf(self.rows_affected).value(); @@ -2570,25 +2547,6 @@ define('tools.querytool', [ } }, - // This function will return the total query execution Time. - get_query_run_time: function(start_time, end_time) { - // Calculate the difference in milliseconds - var difference_ms, miliseconds; - difference_ms = miliseconds = end_time.getTime() - start_time.getTime(); - //take out milliseconds - difference_ms = difference_ms / 1000; - var seconds = Math.floor(difference_ms % 60); - difference_ms = difference_ms / 60; - var minutes = Math.floor(difference_ms % 60); - - if (minutes > 0) - return minutes + ' min'; - else if (seconds > 0) { - return seconds + ' secs'; - } else - return miliseconds + ' msec'; - }, - /* This function is used to check whether cell * is editable or not depending on primary keys * and staged_rows flag diff --git a/web/regression/javascript/sqleditor/calculate_query_run_time_spec.js b/web/regression/javascript/sqleditor/calculate_query_run_time_spec.js new file mode 100644 index 000000000..c1ed5c57e --- /dev/null +++ b/web/regression/javascript/sqleditor/calculate_query_run_time_spec.js @@ -0,0 +1,82 @@ +///////////////////////////////////////////////////////////// +// +// pgAdmin 4 - PostgreSQL Tools +// +// Copyright (C) 2013 - 2018, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +////////////////////////////////////////////////////////////// + +import moment from 'moment'; +import {calculateQueryRunTime} from '../../../pgadmin/static/js/sqleditor/calculate_query_run_time'; + +describe('#calculateQueryRunTime', () => { + describe('time difference is smaller then 1 second', () => { + it('displays milliseconds', () => { + let startDate = moment({ + years:2018, + months:4, + date:2, + hours:10, + minutes:30, + seconds:20, + milliseconds:123}).toDate(); + let endDate = moment({ + years:2018, + months:4, + date:2, + hours:10, + minutes:30, + seconds:21, + milliseconds:70}).toDate(); + expect(calculateQueryRunTime(startDate, endDate)) + .toEqual('947 msec'); + }); + }); + + describe('time difference is smaller then 1 minute', () => { + it('displays milliseconds', () => { + let startDate = moment({ + years:2018, + months:4, + date:2, + hours:10, + minutes:30, + seconds:20, + milliseconds:123}).toDate(); + let endDate = moment({ + years:2018, + months:4, + date:2, + hours:10, + minutes:31, + seconds:15, + milliseconds:70}).toDate(); + expect(calculateQueryRunTime(startDate, endDate)) + .toEqual('54 secs 947 msec'); + }); + }); + + describe('time difference is bigger then 1 minute', () => { + it('displays milliseconds', () => { + let startDate = moment({ + years:2018, + months:4, + date:2, + hours:10, + minutes:30, + seconds:20, + milliseconds:123}).toDate(); + let endDate = moment({ + years:2018, + months:4, + date:2, + hours:10, + minutes:40, + seconds:15, + milliseconds:70}).toDate(); + expect(calculateQueryRunTime(startDate, endDate)) + .toEqual('9 min 54 secs'); + }); + }); +}); diff --git a/web/regression/javascript/sqleditor/call_render_after_poll_spec.js b/web/regression/javascript/sqleditor/call_render_after_poll_spec.js new file mode 100644 index 000000000..9b2509560 --- /dev/null +++ b/web/regression/javascript/sqleditor/call_render_after_poll_spec.js @@ -0,0 +1,203 @@ +///////////////////////////////////////////////////////////// +// +// pgAdmin 4 - PostgreSQL Tools +// +// Copyright (C) 2013 - 2018, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +////////////////////////////////////////////////////////////// + +import {callRenderAfterPoll} from '../../../pgadmin/static/js/sqleditor/call_render_after_poll'; +import moment from 'moment'; + +describe('#callRenderAfterPoll', () => { + let sqlEditorSpy, queryResult, alertify; + beforeEach(() => { + let today = moment('2018-01-01 10:12:31').toDate(); + jasmine.clock().install(); + jasmine.clock().mockDate(today); + sqlEditorSpy = { + _render: jasmine.createSpy('SQLEditor._render'), + setIsQueryRunning: jasmine.createSpy('SQLEditor.setIsQueryRunning'), + trigger: jasmine.createSpy('SQLEditor.trigger'), + update_msg_history: jasmine.createSpy('SQLEditor.update_msg_history'), + disable_tool_buttons: jasmine.createSpy('SQLEditor.disable_tool_buttons'), + query_start_time: new Date(), + }; + alertify = jasmine.createSpyObj('alertify', ['success']); + }); + + afterEach(function () { + jasmine.clock().uninstall(); + }); + + describe('it is not a query tool', () => { + beforeEach(() => { + sqlEditorSpy.is_query_tool = false; + }); + + describe('query was successful but had no result to display', () => { + beforeEach(() => { + queryResult = { + rows_affected: 10, + has_more_rows: false, + colinfo: {}, + }; + }); + + it('renders the the editor', () => { + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(sqlEditorSpy._render).toHaveBeenCalledWith(queryResult); + }); + + it('inform sqleditor that the query stopped running', () => { + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(sqlEditorSpy.setIsQueryRunning).toHaveBeenCalledWith(false); + }); + + it('hides the loading icon', () => { + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(sqlEditorSpy.trigger).toHaveBeenCalledWith('pgadmin-sqleditor:loading-icon:hide'); + }); + }); + + describe('query was successful and have results', () => { + beforeEach(() => { + queryResult = { + rows_affected: 10, + has_more_rows: false, + colinfo: undefined, + result: 'Some result', + }; + }); + + it('saves execution information in the history', () => { + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(sqlEditorSpy.update_msg_history).toHaveBeenCalledWith( + true, + 'Some result\n\nQuery returned successfully in 0 msec.', + false + ); + }); + + it('inform sqleditor that the query stopped running', () => { + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(sqlEditorSpy.setIsQueryRunning).toHaveBeenCalledWith(false); + }); + + it('hides the loading icon', () => { + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(sqlEditorSpy.trigger).toHaveBeenCalledWith('pgadmin-sqleditor:loading-icon:hide'); + }); + + describe('notifications are enabled', () => { + it('display notification', () => { + sqlEditorSpy.info_notifier_timeout = 10; + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(alertify.success).toHaveBeenCalledWith( + 'Query returned successfully in 0 msec.', + 10 + ); + }); + }); + }); + }); + + describe('it is a query tool', () => { + beforeEach(() => { + sqlEditorSpy.is_query_tool = true; + }); + + describe('query was successful but had no result to display', () => { + beforeEach(() => { + queryResult = { + rows_affected: 10, + has_more_rows: false, + colinfo: {}, + }; + }); + + it('renders the the editor', () => { + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(sqlEditorSpy._render).toHaveBeenCalledWith(queryResult); + }); + + it('inform sqleditor that the query stopped running', () => { + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(sqlEditorSpy.setIsQueryRunning).toHaveBeenCalledWith(false); + }); + + it('hides the loading icon', () => { + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(sqlEditorSpy.trigger).toHaveBeenCalledWith('pgadmin-sqleditor:loading-icon:hide'); + }); + + it('enables sqleditor tools buttons', () => { + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(sqlEditorSpy.disable_tool_buttons).toHaveBeenCalledWith(false); + }); + }); + + describe('query was successful and have results', () => { + beforeEach(() => { + queryResult = { + rows_affected: 10, + has_more_rows: false, + colinfo: undefined, + result: 'Some result', + }; + }); + + it('saves execution information in the history', () => { + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(sqlEditorSpy.update_msg_history).toHaveBeenCalledWith( + true, + 'Some result\n\nQuery returned successfully in 0 msec.', + false + ); + }); + + it('inform sqleditor that the query stopped running', () => { + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(sqlEditorSpy.setIsQueryRunning).toHaveBeenCalledWith(false); + }); + + it('hides the loading icon', () => { + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(sqlEditorSpy.trigger).toHaveBeenCalledWith('pgadmin-sqleditor:loading-icon:hide'); + }); + + it('enables sqleditor tools buttons', () => { + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(sqlEditorSpy.disable_tool_buttons).toHaveBeenCalledWith(false); + }); + + describe('notifications are enabled', () => { + it('display notification', () => { + sqlEditorSpy.info_notifier_timeout = 10; + callRenderAfterPoll(sqlEditorSpy, alertify, queryResult); + + expect(alertify.success).toHaveBeenCalledWith( + 'Query returned successfully in 0 msec.', + 10 + ); + }); + }); + }); + }); +}); diff --git a/web/yarn.lock b/web/yarn.lock index 88edeb1f8..da5e5f645 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -7422,7 +7422,7 @@ sprintf-js@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.0.tgz#cffcaf702daf65ea39bb4e0fa2b299cec1a1be46" -sprintf-js@^1.0.3: +sprintf-js@^1.0.3, sprintf-js@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c"