mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Use on-demand loading for results in the query tool. Fixes #2137
With a 27420 row query, pgAdmin III runs the query in 5.873s on my laptop. pgAdmin 4 now takes ~1s.
This commit is contained in:
committed by
Dave Page
parent
15cb9fc35b
commit
c65158312d
@@ -3,6 +3,7 @@ import 'slickgrid/slick-default-theme.css';
|
||||
import 'slickgrid/css/smoothness/jquery-ui-1.11.3.custom.css';
|
||||
import 'slickgrid/slick.core';
|
||||
import 'slickgrid/slick.grid';
|
||||
import 'slickgrid/slick.dataview';
|
||||
import 'slickgrid/slick.editors';
|
||||
import 'slickgrid/slick.formatters';
|
||||
import 'slickgrid/plugins/slick.autotooltips';
|
||||
|
||||
@@ -4,13 +4,18 @@ define([
|
||||
'slickgrid',
|
||||
], function ($, RangeSelectionHelper) {
|
||||
var ColumnSelector = function () {
|
||||
var Slick = window.Slick;
|
||||
var gridEventBus = new Slick.EventHandler();
|
||||
var Slick = window.Slick,
|
||||
gridEventBus = new Slick.EventHandler(),
|
||||
onBeforeColumnSelectAll = new Slick.Event(),
|
||||
onColumnSelectAll = new Slick.Event();
|
||||
|
||||
var init = function (grid) {
|
||||
gridEventBus.subscribe(grid.onHeaderClick, handleHeaderClick.bind(null, grid));
|
||||
grid.getSelectionModel().onSelectedRangesChanged
|
||||
.subscribe(handleSelectedRangesChanged.bind(null, grid));
|
||||
onColumnSelectAll.subscribe(function(e, args) {
|
||||
updateRanges(args.grid, args.column.id);
|
||||
});
|
||||
};
|
||||
|
||||
var handleHeaderClick = function (grid, event, args) {
|
||||
@@ -21,11 +26,20 @@ define([
|
||||
if (isColumnSelectable(columnDefinition)) {
|
||||
var $columnHeader = $(event.target);
|
||||
if (hasClickedChildOfColumnHeader(event)) {
|
||||
if ($(event.target).hasClass('slick-resizable-handle')) {
|
||||
return;
|
||||
}
|
||||
$columnHeader = $(event.target).parents('.slick-header-column');
|
||||
}
|
||||
$columnHeader.toggleClass('selected');
|
||||
|
||||
updateRanges(grid, columnDefinition.id);
|
||||
if ($columnHeader.hasClass('selected')) {
|
||||
onBeforeColumnSelectAll.notify(args, event);
|
||||
}
|
||||
|
||||
if (!(event.isPropagationStopped() || event.isImmediatePropagationStopped())) {
|
||||
updateRanges(grid, columnDefinition.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -107,6 +121,8 @@ define([
|
||||
$.extend(this, {
|
||||
'init': init,
|
||||
'getColumnDefinitions': getColumnDefinitions,
|
||||
'onBeforeColumnSelectAll': onBeforeColumnSelectAll,
|
||||
'onColumnSelectAll': onColumnSelectAll,
|
||||
});
|
||||
};
|
||||
return ColumnSelector;
|
||||
|
||||
@@ -12,19 +12,19 @@ function ($, _, clipboard, RangeSelectionHelper, rangeBoundaryNavigator) {
|
||||
var grid = self.slickgrid;
|
||||
var columnDefinitions = grid.getColumns();
|
||||
var selectedRanges = grid.getSelectionModel().getSelectedRanges();
|
||||
var data = grid.getData();
|
||||
var dataView = grid.getData();
|
||||
var rows = grid.getSelectedRows();
|
||||
|
||||
if (RangeSelectionHelper.areAllRangesCompleteRows(grid, selectedRanges)) {
|
||||
self.copied_rows = rows.map(function (rowIndex) {
|
||||
return data[rowIndex];
|
||||
return grid.getDataItem(rowIndex);
|
||||
});
|
||||
setPasteRowButtonEnablement(self.can_edit, true);
|
||||
} else {
|
||||
self.copied_rows = [];
|
||||
setPasteRowButtonEnablement(self.can_edit, false);
|
||||
}
|
||||
var csvText = rangeBoundaryNavigator.rangesToCsv(data, columnDefinitions, selectedRanges);
|
||||
var csvText = rangeBoundaryNavigator.rangesToCsv(dataView.getItems(), columnDefinitions, selectedRanges);
|
||||
if (csvText) {
|
||||
clipboard.copyTextToClipboard(csvText);
|
||||
}
|
||||
|
||||
@@ -6,21 +6,31 @@ define(['jquery',
|
||||
'sources/url_for',
|
||||
], function ($, gettext, ColumnSelector, RowSelector, RangeSelectionHelper, url_for) {
|
||||
var GridSelector = function (columnDefinitions) {
|
||||
var rowSelector = new RowSelector(columnDefinitions);
|
||||
var columnSelector = new ColumnSelector(columnDefinitions);
|
||||
var Slick = window.Slick,
|
||||
rowSelector = new RowSelector(columnDefinitions),
|
||||
columnSelector = new ColumnSelector(columnDefinitions),
|
||||
onBeforeGridSelectAll = new Slick.Event(),
|
||||
onGridSelectAll = new Slick.Event(),
|
||||
onBeforeGridColumnSelectAll = columnSelector.onBeforeColumnSelectAll,
|
||||
onGridColumnSelectAll = columnSelector.onColumnSelectAll;
|
||||
|
||||
var init = function (grid) {
|
||||
this.grid = grid;
|
||||
grid.onHeaderClick.subscribe(function (event, eventArguments) {
|
||||
if (eventArguments.column.selectAllOnClick) {
|
||||
toggleSelectAll(grid);
|
||||
if (eventArguments.column.selectAllOnClick && !$(event.target).hasClass('slick-resizable-handle')) {
|
||||
toggleSelectAll(grid, event, eventArguments);
|
||||
}
|
||||
});
|
||||
|
||||
grid.getSelectionModel().onSelectedRangesChanged
|
||||
.subscribe(handleSelectedRangesChanged.bind(null, grid));
|
||||
.subscribe(handleSelectedRangesChanged.bind(null, grid));
|
||||
|
||||
grid.registerPlugin(rowSelector);
|
||||
grid.registerPlugin(columnSelector);
|
||||
|
||||
onGridSelectAll.subscribe(function(e, args) {
|
||||
RangeSelectionHelper.selectAll(args.grid);
|
||||
});
|
||||
};
|
||||
|
||||
var getColumnDefinitions = function (columnDefinitions) {
|
||||
@@ -45,11 +55,14 @@ define(['jquery',
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSelectAll(grid) {
|
||||
function toggleSelectAll(grid, event, eventArguments) {
|
||||
if (RangeSelectionHelper.isEntireGridSelected(grid)) {
|
||||
selectNone(grid);
|
||||
} else {
|
||||
RangeSelectionHelper.selectAll(grid);
|
||||
onBeforeGridSelectAll.notify(eventArguments, event);
|
||||
if (!(event.isPropagationStopped() || event.isImmediatePropagationStopped())) {
|
||||
RangeSelectionHelper.selectAll(grid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +74,10 @@ define(['jquery',
|
||||
$.extend(this, {
|
||||
'init': init,
|
||||
'getColumnDefinitions': getColumnDefinitions,
|
||||
'onBeforeGridSelectAll': onBeforeGridSelectAll,
|
||||
'onGridSelectAll': onGridSelectAll,
|
||||
'onBeforeGridColumnSelectAll': onBeforeGridColumnSelectAll,
|
||||
'onGridColumnSelectAll': onGridColumnSelectAll,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ function (RangeSelectionHelper) {
|
||||
},
|
||||
|
||||
rangesToCsv: function (data, columnDefinitions, selectedRanges) {
|
||||
|
||||
var rowRangeBounds = selectedRanges.map(function (range) {
|
||||
return [range.fromRow, range.toRow];
|
||||
});
|
||||
@@ -72,6 +73,7 @@ function (RangeSelectionHelper) {
|
||||
var csvRows = this.mapOver2DArray(rowRangeBounds, colRangeBounds, this.csvCell.bind(this, data, columnDefinitions), function (rowData) {
|
||||
return rowData.join(',');
|
||||
});
|
||||
|
||||
return csvRows.join('\n');
|
||||
},
|
||||
|
||||
@@ -101,7 +103,7 @@ function (RangeSelectionHelper) {
|
||||
},
|
||||
|
||||
csvCell: function (data, columnDefinitions, rowId, colId) {
|
||||
var val = data[rowId][columnDefinitions[colId].pos];
|
||||
var val = data[rowId][columnDefinitions[colId].field];
|
||||
|
||||
if (val && _.isObject(val)) {
|
||||
val = '\'' + JSON.stringify(val) + '\'';
|
||||
|
||||
@@ -82,7 +82,8 @@ define([
|
||||
formatter: function (rowIndex) {
|
||||
return '<span ' +
|
||||
'data-row="' + rowIndex + '" ' +
|
||||
'data-cell-type="row-header-selector"/>';
|
||||
'data-cell-type="row-header-selector">' +
|
||||
(rowIndex+1) + '</span>';
|
||||
},
|
||||
width: 30,
|
||||
});
|
||||
|
||||
@@ -22,53 +22,44 @@ define(
|
||||
$(selector).prop('disabled', false);
|
||||
}
|
||||
|
||||
function getRowPrimaryKeyValuesToStage(selectedRows, primaryKeyColumnIndices, gridData) {
|
||||
function getRowPrimaryKeyValuesToStage(selectedRows, primaryKeys, dataView, client_primary_key) {
|
||||
return _.reduce(selectedRows, function (primaryKeyValuesToStage, dataGridRowIndex) {
|
||||
var gridRow = gridData[dataGridRowIndex];
|
||||
|
||||
if (isRowMissingPrimaryKeys(gridRow, primaryKeyColumnIndices)) {
|
||||
var gridRow = dataView.getItem(dataGridRowIndex);
|
||||
if (isRowMissingPrimaryKeys(gridRow, primaryKeys)) {
|
||||
return primaryKeyValuesToStage;
|
||||
}
|
||||
|
||||
var tempPK = gridRow.__temp_PK;
|
||||
primaryKeyValuesToStage[tempPK] = getSingleRowPrimaryKeyValueToStage(primaryKeyColumnIndices, gridRow);
|
||||
|
||||
var tempPK = gridRow[client_primary_key];
|
||||
primaryKeyValuesToStage[tempPK] = getSingleRowPrimaryKeyValueToStage(primaryKeys, gridRow);
|
||||
return primaryKeyValuesToStage;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function isRowMissingPrimaryKeys(gridRow, primaryKeyColumnIndices) {
|
||||
function isRowMissingPrimaryKeys(gridRow, primaryKeys) {
|
||||
if (_.isUndefined(gridRow)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !_.isUndefined(
|
||||
_.find(primaryKeyColumnIndices, function (pkIndex) {
|
||||
return _.isUndefined(gridRow[pkIndex]);
|
||||
_.find(primaryKeys , function (pk) {
|
||||
return _.isUndefined(gridRow[pk]);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function getSingleRowPrimaryKeyValueToStage(primaryKeyColumnIndices, gridRow) {
|
||||
function getSingleRowPrimaryKeyValueToStage(primaryKeys, gridRow) {
|
||||
var rowToStage = {};
|
||||
if (primaryKeyColumnIndices.length) {
|
||||
_.each(_.keys(gridRow), function (columnPos) {
|
||||
if (_.contains(primaryKeyColumnIndices, Number(columnPos)))
|
||||
rowToStage[columnPos] = gridRow[columnPos];
|
||||
if (primaryKeys && primaryKeys.length) {
|
||||
_.each(_.keys(gridRow), function (columnNames) {
|
||||
if (_.contains(primaryKeys, columnNames))
|
||||
rowToStage[columnNames] = gridRow[columnNames];
|
||||
});
|
||||
}
|
||||
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);
|
||||
|
||||
var dataView = self.grid.getData();
|
||||
var stagedRows = getRowPrimaryKeyValuesToStage(selectedRows, _.keys(self.keys), dataView, self.client_primary_key);
|
||||
return stagedRows;
|
||||
}
|
||||
|
||||
@@ -114,4 +105,4 @@ define(
|
||||
};
|
||||
return setStagedRows;
|
||||
}
|
||||
);
|
||||
);
|
||||
@@ -76,18 +76,18 @@
|
||||
last_value = (column_type === 'number') ?
|
||||
(_.isEmpty(last_value) || last_value) : last_value;
|
||||
|
||||
item[args.column.pos] = state;
|
||||
item[args.column.field] = state;
|
||||
if (last_value && _.isNull(state) &&
|
||||
(_.isUndefined(grid.copied_rows[row]) ||
|
||||
_.isUndefined(grid.copied_rows[row][cell]))
|
||||
) {
|
||||
item[args.column.pos] = undefined;
|
||||
item[args.column.field] = undefined;
|
||||
if (grid.copied_rows[row] == undefined) grid.copied_rows[row] = [];
|
||||
grid.copied_rows[row][cell] = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
item[args.column.pos] = state;
|
||||
item[args.column.field] = state;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,14 +189,14 @@
|
||||
this.loadValue = function (item) {
|
||||
var col = args.column;
|
||||
|
||||
if (_.isUndefined(item[args.column.pos]) && col.has_default_val) {
|
||||
if (_.isUndefined(item[args.column.field]) && col.has_default_val) {
|
||||
$input.val(defaultValue = "");
|
||||
}
|
||||
else if (item[args.column.pos] === "") {
|
||||
else if (item[args.column.field] === "") {
|
||||
$input.val(defaultValue = "''");
|
||||
}
|
||||
else {
|
||||
$input.val(defaultValue = item[args.column.pos]);
|
||||
$input.val(defaultValue = item[args.column.field]);
|
||||
$input.select();
|
||||
}
|
||||
};
|
||||
@@ -323,7 +323,7 @@
|
||||
};
|
||||
|
||||
this.loadValue = function (item) {
|
||||
var data = defaultValue = item[args.column.pos];
|
||||
var data = defaultValue = item[args.column.field];
|
||||
if (data && typeof data === "object" && !Array.isArray(data)) {
|
||||
data = JSON.stringify(data);
|
||||
} else if (Array.isArray(data)) {
|
||||
@@ -443,7 +443,7 @@
|
||||
};
|
||||
|
||||
this.loadValue = function (item) {
|
||||
$input.val(defaultValue = item[args.column.pos]);
|
||||
$input.val(defaultValue = item[args.column.field]);
|
||||
$input.select();
|
||||
};
|
||||
|
||||
@@ -452,7 +452,7 @@
|
||||
};
|
||||
|
||||
this.applyValue = function (item, state) {
|
||||
item[args.column.pos] = state;
|
||||
item[args.column.field] = state;
|
||||
};
|
||||
|
||||
this.isValueChanged = function () {
|
||||
@@ -531,13 +531,13 @@
|
||||
};
|
||||
|
||||
this.loadValue = function (item) {
|
||||
defaultValue = item[args.column.pos];
|
||||
if (_.isNull(defaultValue)|| _.isUndefined(defaultValue)) {
|
||||
defaultValue = item[args.column.field];
|
||||
if (_.isNull(defaultValue)||_.isUndefined(defaultValue)) {
|
||||
$select.prop('indeterminate', true);
|
||||
$select.data('checked', 2);
|
||||
}
|
||||
else {
|
||||
defaultValue = !!item[args.column.pos];
|
||||
defaultValue = !!item[args.column.field];
|
||||
if (defaultValue) {
|
||||
$select.prop('checked', true);
|
||||
$select.data('checked', 0);
|
||||
@@ -556,7 +556,7 @@
|
||||
};
|
||||
|
||||
this.applyValue = function (item, state) {
|
||||
item[args.column.pos] = state;
|
||||
item[args.column.field] = state;
|
||||
};
|
||||
|
||||
this.isValueChanged = function () {
|
||||
@@ -648,7 +648,7 @@
|
||||
};
|
||||
|
||||
this.loadValue = function (item) {
|
||||
var data = defaultValue = item[args.column.pos];
|
||||
var data = defaultValue = item[args.column.field];
|
||||
if (typeof data === "object" && !Array.isArray(data)) {
|
||||
data = JSON.stringify(data);
|
||||
} else if (Array.isArray(data)) {
|
||||
@@ -671,7 +671,7 @@
|
||||
};
|
||||
|
||||
this.applyValue = function (item, state) {
|
||||
item[args.column.pos] = state;
|
||||
item[args.column.field] = state;
|
||||
};
|
||||
|
||||
this.isValueChanged = function () {
|
||||
@@ -725,7 +725,7 @@
|
||||
};
|
||||
|
||||
this.loadValue = function (item) {
|
||||
var value = item[args.column.pos];
|
||||
var value = item[args.column.field];
|
||||
|
||||
// Check if value is null or undefined
|
||||
if (value === undefined && typeof value === "undefined") {
|
||||
@@ -858,7 +858,7 @@
|
||||
};
|
||||
|
||||
this.loadValue = function (item) {
|
||||
defaultValue = item[args.column.pos];
|
||||
defaultValue = item[args.column.field];
|
||||
$input.val(defaultValue);
|
||||
$input[0].defaultValue = defaultValue;
|
||||
$input.select();
|
||||
|
||||
Reference in New Issue
Block a user